home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / share / hplip / base / device.py < prev    next >
Encoding:
Python Source  |  2009-04-14  |  84.8 KB  |  2,501 lines

  1. # -*- coding: utf-8 -*-
  2. #
  3. # (c) Copyright 2003-2009 Hewlett-Packard Development Company, L.P.
  4. #
  5. # This program is free software; you can redistribute it and/or modify
  6. # it under the terms of the GNU General Public License as published by
  7. # the Free Software Foundation; either version 2 of the License, or
  8. # (at your option) any later version.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. # GNU General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU General Public License
  16. # along with this program; if not, write to the Free Software
  17. # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  18. #
  19. # Author: Don Welch
  20. #
  21.  
  22. # Std Lib
  23. import socket
  24. import re
  25. import gzip
  26. import os.path
  27. import time
  28. import urllib # TODO: Replace with urllib2 (urllib is deprecated in Python 3.0)
  29. import StringIO
  30. import httplib
  31. import struct
  32.  
  33. # Local
  34. from g import *
  35. from codes import *
  36. import utils
  37. import status
  38. import pml
  39. from prnt import pcl, ldl, cups
  40. import models, mdns, slp
  41. from strings import StringTable
  42.  
  43.  
  44. try:
  45.     import hpmudext
  46. except ImportError:
  47.     if not os.getenv("HPLIP_BUILD"):
  48.         log.error("HPMUDEXT could not be loaded. Please check HPLIP installation.")
  49.         sys.exit(1)
  50.  
  51.  
  52. dbus_avail = False
  53. dbus_disabled = False
  54. try:
  55.     import dbus
  56.     from dbus import lowlevel, SessionBus
  57.     dbus_avail = True
  58. except ImportError:
  59.     log.warn("python-dbus not installed.")
  60.  
  61.  
  62. DEFAULT_PROBE_BUS = ['usb', 'par', 'cups']
  63. VALID_BUSES = ('par', 'net', 'cups', 'usb') #, 'bt', 'fw')
  64. VALID_BUSES_WO_CUPS = ('par', 'net', 'usb')
  65. DEFAULT_FILTER = None
  66. VALID_FILTERS = ('print', 'scan', 'fax', 'pcard', 'copy')
  67. DEFAULT_BE_FILTER = ('hp',)
  68.  
  69. pat_deviceuri = re.compile(r"""(.*):/(.*?)/(\S*?)\?(?:serial=(\S*)|device=(\S*)|ip=(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}[^&]*))(?:&port=(\d))?""", re.IGNORECASE)
  70. http_pat_url = re.compile(r"""/(.*?)/(\S*?)\?(?:serial=(\S*)|device=(\S*))&loc=(\S*)""", re.IGNORECASE)
  71. direct_pat = re.compile(r'direct (.*?) "(.*?)" "(.*?)" "(.*?)"', re.IGNORECASE)
  72.  
  73. # Pattern to check for ; at end of CTR fields
  74. # Note: If ; not present, CTR value is invalid
  75. pat_dynamic_ctr = re.compile(r"""CTR:\d*\s.*;""", re.IGNORECASE)
  76.  
  77. MAX_BUFFER = 8192
  78.  
  79. # Cache for model data
  80. model_dat = models.ModelData()
  81.  
  82. ip_pat = re.compile(r"""\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b""", re.IGNORECASE)
  83.  
  84. dev_pat = re.compile(r"""/dev/.+""", re.IGNORECASE)
  85. usb_pat = re.compile(r"""(\d+):(\d+)""", re.IGNORECASE)
  86.  
  87. #
  88. # Event Wrapper Class for pipe IPC
  89. #
  90.  
  91. class Event(object):
  92.     def __init__(self, device_uri, printer_name, event_code,
  93.                  username=prop.username, job_id=0, title='',
  94.                  timedate=0):
  95.  
  96.         self.device_uri = unicode(utils.xrstrip(device_uri, '\x00'))[:64].encode('utf-8')
  97.         self.printer_name = unicode(utils.xrstrip(printer_name, '\x00'))[:64].encode('utf-8')
  98.         self.event_code = int(event_code)
  99.         self.username = unicode(utils.xrstrip(username, '\x00'))[:32].encode('utf-8')
  100.         self.job_id = int(job_id)
  101.         self.title = unicode(utils.xrstrip(title, '\x00'))[:64].encode('utf-8')
  102.  
  103.         if timedate:
  104.             self.timedate = float(timedate)
  105.         else:
  106.             self.timedate = time.time()
  107.  
  108.         self.pipe_fmt = "64s64sI32sI64sf"
  109.         self.dbus_fmt = "ssisisd"
  110.  
  111.  
  112.     def debug(self):
  113.         log.debug("    device_uri=%s" % self.device_uri)
  114.         log.debug("    printer_name=%s" % self.printer_name)
  115.         log.debug("    event_code=%d" % self.event_code)
  116.         log.debug("    username=%s" % self.username)
  117.         log.debug("    job_id=%d" % self.job_id)
  118.         log.debug("    title=%s" % self.title)
  119.         log.debug("    timedate=%s" % self.timedate)
  120.  
  121.  
  122.     def pack_for_pipe(self):
  123.         return struct.pack(self.pipe_fmt, self.device_uri, self.printer_name,
  124.                 self.event_code, self.username, self.job_id, self.title,
  125.                 self.timedate)
  126.  
  127.  
  128.     def send_via_pipe(self, fd, recipient='hpssd'):
  129.         if fd is not None:
  130.             log.debug("Sending event %d to %s (via pipe %d)..." % (self.event_code, recipient, fd))
  131.             try:
  132.                 os.write(fd, self.pack_for_pipe())
  133.                 return True
  134.             except OSError:
  135.                 log.debug("Failed.")
  136.                 return False
  137.  
  138.  
  139.     def send_via_dbus(self, session_bus, interface='com.hplip.StatusService'):
  140.         if session_bus is not None and dbus_avail:
  141.             log.debug("Sending event %d to %s (via dbus)..." % (self.event_code, interface))
  142.             msg = lowlevel.SignalMessage('/', interface, 'Event')
  143.             msg.append(signature=self.dbus_fmt, *self.as_tuple())
  144.             session_bus.send_message(msg)
  145.  
  146.  
  147.     def copy(self):
  148.         return Event(*self.as_tuple())
  149.  
  150.  
  151.     def __str__(self):
  152.         return "<Event('%s', '%s', %d, '%s', %d, '%s', %f)>" % self.as_tuple()
  153.  
  154.  
  155.     def as_tuple(self):
  156.         return (self.device_uri, self.printer_name, self.event_code,
  157.              self.username, self.job_id, self.title, self.timedate)
  158.  
  159.  
  160. class FaxEvent(Event):
  161.     def __init__(self, temp_file, event):
  162.         Event.__init__(self, *event.as_tuple())
  163.         self.temp_file = temp_file
  164.         self.pipe_fmt = "64s64sI32sI64sfs"
  165.         self.dbus_fmt = "ssisisfs"
  166.  
  167.  
  168.     def debug(self):
  169.         log.debug("FAX:")
  170.         Event.debug(self)
  171.         log.debug("    temp_file=%s" % self.temp_file)
  172.  
  173.  
  174.     def __str__(self):
  175.         return "<FaxEvent('%s', '%s', %d, '%s', %d, '%s', %f, '%s')>" % self.as_tuple()
  176.  
  177.  
  178.     def as_tuple(self):
  179.         return (self.device_uri, self.printer_name, self.event_code,
  180.              self.username, self.job_id, self.title, self.timedate,
  181.              self.temp_file)
  182.  
  183.  
  184.  
  185. class DeviceIOEvent(Event):
  186.     def __init__(self, bytes_written, event):
  187.         Event.__init__(self, *event.as_tuple())
  188.         self.bytes_written = bytes_written
  189.         self.pipe_fmt = "64s64sI32sI64sfI"
  190.         self.dbus_fmt = "ssisisfi"
  191.  
  192.  
  193.     def debug(self):
  194.         log.debug("DEVIO:")
  195.         Event.debug(self)
  196.         log.debug("    bytes_written=%d" % self.bytes_written)
  197.  
  198.  
  199.     def __str__(self):
  200.         return "<DeviceIOEvent('%s', '%s', %d, '%s', %d, '%s', %f, '%d')>" % self.as_tuple()
  201.  
  202.  
  203.     def as_tuple(self):
  204.         return (self.device_uri, self.printer_name, self.event_code,
  205.              self.username, self.job_id, self.title, self.timedate,
  206.              self.bytes_written)
  207.  
  208.  
  209. #
  210. # DBus Support
  211. #
  212.  
  213. def init_dbus(dbus_loop=None):
  214.     global dbus_avail
  215.     service = None
  216.     session_bus = None
  217.  
  218.     if not prop.gui_build:
  219.         dbus_avail = False
  220.         return dbus_avail, None,  None
  221.  
  222.     if dbus_avail and not dbus_disabled:
  223.         if os.getuid() == 0:
  224.             log.debug("Not starting dbus: running as root.")
  225.             dbus_avail = False
  226.             return dbus_avail, None,  None
  227.  
  228.         try:
  229.             if dbus_loop is None:
  230.                 session_bus = dbus.SessionBus()
  231.             else:
  232.                 session_bus = dbus.SessionBus(dbus_loop)
  233.         except dbus.exceptions.DBusException, e:
  234.             if os.getuid() != 0:
  235.                 log.error("Unable to connect to dbus session bus.")
  236.             else:
  237.                 log.debug("Unable to connect to dbus session bus (running as root?)")
  238.  
  239.             dbus_avail = False
  240.             return dbus_avail, None,  None
  241.  
  242.         try:
  243.             log.debug("Connecting to com.hplip.StatusService (try #1)...")
  244.             service = session_bus.get_object('com.hplip.StatusService', "/com/hplip/StatusService")
  245.             dbus_avail = True
  246.         except dbus.exceptions.DBusException, e:
  247.             try:
  248.                 os.waitpid(-1, os.WNOHANG)
  249.             except OSError:
  250.                 pass
  251.  
  252.             path = utils.which('hp-systray')
  253.             if path:
  254.                 path = os.path.join(path, 'hp-systray')
  255.             else:
  256.                 path = os.path.join(prop.home_dir, 'systray.py')
  257.                 if not os.path.exists(path):
  258.                     log.warn("Unable to start hp-systray")
  259.                     return False, None,  None
  260.  
  261.             log.debug("Running hp-systray: %s --force-startup" % path)
  262.  
  263.             os.spawnlp(os.P_NOWAIT, path, 'hp-systray', '--force-startup')
  264.  
  265.             log.debug("Waiting for hp-systray to start...")
  266.             time.sleep(1)
  267.  
  268.             t = 2
  269.             while True:
  270.                 try:
  271.                     log.debug("Connecting to com.hplip.StatusService (try #%d)..." % t)
  272.                     service = session_bus.get_object('com.hplip.StatusService', "/com/hplip/StatusService")
  273.  
  274.                 except dbus.exceptions.DBusException, e:
  275.                     log.debug("Unable to connect to dbus. Is hp-systray running?")
  276.                     t += 1
  277.  
  278.                     if t > 5:
  279.                         log.warn("Unable to connect to dbus. Is hp-systray running?")
  280.                         return False, None,  None
  281.  
  282.                     time.sleep(1)
  283.  
  284.                 else:
  285.                     log.debug("Connected.")
  286.                     dbus_avail = True
  287.                     break
  288.  
  289.     return dbus_avail, service,  session_bus
  290.  
  291.  
  292. #
  293. # Make URI from parameter (bus ID, IP address, etc)
  294. #
  295.  
  296. def makeURI(param, port=1):
  297.     cups_uri, sane_uri, fax_uri = '', '', ''
  298.     found = False
  299.  
  300.     # see if the param represents a hostname
  301.     try:
  302.         param = socket.gethostbyname(param)
  303.     except socket.gaierror:
  304.         log.debug("Gethostbyname() failed. Trying other patterns...")
  305.  
  306.     if dev_pat.search(param) is not None: # parallel
  307.         log.debug("Trying parallel with %s" % param)
  308.  
  309.         result_code, uri = hpmudext.make_par_uri(param)
  310.  
  311.         if result_code == hpmudext.HPMUD_R_OK and uri:
  312.             log.debug("Found: %s" % uri)
  313.             found = True
  314.             cups_uri = uri
  315.         else:
  316.             log.debug("Not found.")
  317.  
  318.     elif usb_pat.search(param) is not None: # USB
  319.         match_obj = usb_pat.search(param)
  320.         usb_bus_id = match_obj.group(1)
  321.         usb_dev_id = match_obj.group(2)
  322.  
  323.         log.debug("Trying USB with bus=%s dev=%s..." % (usb_bus_id, usb_dev_id))
  324.         result_code, uri = hpmudext.make_usb_uri(usb_bus_id, usb_dev_id)
  325.  
  326.         if result_code == ERROR_SUCCESS and uri:
  327.             log.debug("Found: %s" % uri)
  328.             found = True
  329.             cups_uri = uri
  330.         else:
  331.             log.debug("Not found.")
  332.  
  333.     elif ip_pat.search(param) is not None: # IPv4 dotted quad
  334.         log.debug("Trying IP address %s" % param)
  335.  
  336.         result_code, uri = hpmudext.make_net_uri(param, port)
  337.  
  338.         if result_code == hpmudext.HPMUD_R_OK and uri:
  339.             log.debug("Found: %s" % uri)
  340.             found = True
  341.             cups_uri = uri
  342.         else:
  343.             log.debug("Not found.")
  344.  
  345.     else: # serial
  346.         log.debug("Trying serial number %s" % param)
  347.         devices = probeDevices(bus=['usb', 'par'])
  348.  
  349.         for d in devices:
  350.             log.debug(d)
  351.  
  352.             # usb has serial in URI...
  353.             try:
  354.                 back_end, is_hp, bus, model, serial, dev_file, host, port = \
  355.                     parseDeviceURI(d)
  356.             except Error:
  357.                 continue
  358.  
  359.             if bus == 'par': # ...parallel does not. Must get Device ID to obtain it...
  360.                 mq = queryModelByURI(d)
  361.  
  362.                 result_code, device_id = \
  363.                     hpmudext.device_open(d, mq.get('io-mode', hpmudext.HPMUD_UNI_MODE))
  364.  
  365.                 if result_code == hpmudext.HPMUD_R_OK:
  366.                     result_code, data = hpmudext.get_device_id(device_id)
  367.                     serial = parseDeviceID(data).get('SN', '')
  368.                     hpmudext.close_device(device_id)
  369.  
  370.             if serial.lower() == param.lower():
  371.                 log.debug("Found: %s" % d)
  372.                 found = True
  373.                 cups_uri = d
  374.                 break
  375.             else:
  376.                 log.debug("Not found.")
  377.  
  378.     if found:
  379.         try:
  380.             mq = queryModelByURI(cups_uri)
  381.         except Error, e:
  382.             log.error("Error: %s" % e.msg)
  383.             cups_uri, sane_uri, fax_uri = '', '', ''
  384.         else:
  385.             if mq.get('support-type', SUPPORT_TYPE_NONE) > SUPPORT_TYPE_NONE:
  386.                 if mq.get('scan-type', 0):
  387.                     sane_uri = cups_uri.replace("hp:", "hpaio:")
  388.  
  389.                 if mq.get('fax-type', 0):
  390.                     fax_uri = cups_uri.replace("hp:", "hpfax:")
  391.  
  392.             else:
  393.                 cups_uri, sane_uri, fax_uri = '', '', ''
  394.  
  395.     else:
  396.         scan_uri, fax_uri = '', ''
  397.  
  398.     if cups_uri:
  399.         user_conf.set('last_used', 'device_uri', cups_uri)
  400.  
  401.     return cups_uri, sane_uri, fax_uri
  402.  
  403.  
  404. #
  405. # Model Queries
  406. #
  407.  
  408. def queryModelByModel(model):
  409.     model = models.normalizeModelName(model).lower()
  410.     return model_dat[model]
  411.  
  412.  
  413. def queryModelByURI(device_uri):
  414.     try:
  415.         back_end, is_hp, bus, model, \
  416.             serial, dev_file, host, port = \
  417.             parseDeviceURI(device_uri)
  418.     except Error:
  419.         raise Error(ERROR_INVALID_DEVICE_URI)
  420.     else:
  421.         return queryModelByModel(model)
  422.  
  423.  
  424. #
  425. # Device Discovery
  426. #
  427.  
  428. def probeDevices(bus=DEFAULT_PROBE_BUS, timeout=10,
  429.                  ttl=4, filter=DEFAULT_FILTER,  search='', net_search='slp',
  430.                  back_end_filter=('hp',)):
  431.  
  432.     num_devices, ret_devices = 0, {}
  433.  
  434.     if search:
  435.         try:
  436.             search_pat = re.compile(search, re.IGNORECASE)
  437.         except:
  438.             log.error("Invalid search pattern. Search uses standard regular expressions. For more info, see: http://www.amk.ca/python/howto/regex/")
  439.             search = ''
  440.  
  441.     for b in bus:
  442.         log.debug("Probing bus: %s" % b)
  443.         if b not in VALID_BUSES:
  444.             log.error("Invalid bus: %s" % b)
  445.             continue
  446.  
  447.         if b == 'net':
  448.             if net_search == 'slp':
  449.                 try:
  450.                     detected_devices = slp.detectNetworkDevices(ttl, timeout)
  451.                 except Error, socket.error:
  452.                     log.error("An error occured during network probe.")
  453.                     raise ERROR_INTERNAL
  454.             else:
  455.                 try:
  456.                     detected_devices = mdns.detectNetworkDevices(ttl, timeout)
  457.                 except Error, socket.error:
  458.                     log.error("An error occured during network probe.")
  459.                     raise ERROR_INTERNAL
  460.  
  461.             for ip in detected_devices:
  462.                 update_spinner()
  463.                 hn = detected_devices[ip].get('hn', '?UNKNOWN?')
  464.                 num_devices_on_jd = detected_devices[ip].get('num_devices', 0)
  465.                 num_ports_on_jd = detected_devices[ip].get('num_ports', 1)
  466.  
  467.                 if num_devices_on_jd > 0:
  468.                     for port in range(num_ports_on_jd):
  469.                         dev = detected_devices[ip].get('device%d' % (port+1), '0')
  470.  
  471.                         if dev is not None and dev != '0':
  472.                             device_id = parseDeviceID(dev)
  473.                             model = models.normalizeModelName(device_id.get('MDL', '?UNKNOWN?'))
  474.  
  475.                             if num_ports_on_jd == 1:
  476.                                 device_uri = 'hp:/net/%s?ip=%s' % (model, ip)
  477.                             else:
  478.                                 device_uri = 'hp:/net/%s?ip=%s&port=%d' % (model, ip, (port+1))
  479.  
  480.                             include = True
  481.                             mq = queryModelByModel(model)
  482.  
  483.                             if not mq:
  484.                                 log.debug("Not found.")
  485.                                 include = False
  486.  
  487.                             elif int(mq.get('support-type', SUPPORT_TYPE_NONE)) == SUPPORT_TYPE_NONE:
  488.                                 log.debug("Not supported.")
  489.                                 include = False
  490.  
  491.                             elif filter not in (None, 'print', 'print-type'):
  492.                                 include = __checkFilter(filter, mq)
  493.  
  494.                             if include:
  495.                                 ret_devices[device_uri] = (model, model, hn)
  496.  
  497.         elif b in ('usb', 'par'):
  498.             if b == 'par':
  499.                 bn = hpmudext.HPMUD_BUS_PARALLEL
  500.             else:
  501.                 bn = hpmudext.HPMUD_BUS_USB
  502.  
  503.             result_code, data = hpmudext.probe_devices(bn)
  504.  
  505.             if result_code == hpmudext.HPMUD_R_OK:
  506.                 for x in data.splitlines():
  507.                     m = direct_pat.match(x)
  508.  
  509.                     uri = m.group(1) or ''
  510.                     mdl = m.group(2) or ''
  511.                     desc = m.group(3) or ''
  512.                     devid = m.group(4) or ''
  513.  
  514.                     log.debug(uri)
  515.  
  516.                     try:
  517.                         back_end, is_hp, bb, model, serial, dev_file, host, port = \
  518.                             parseDeviceURI(uri)
  519.                     except Error:
  520.                         continue
  521.  
  522.                     include = True
  523.  
  524.                     if mdl and uri and is_hp:
  525.                         mq = queryModelByModel(model)
  526.  
  527.                         if not mq:
  528.                             log.debug("Not found.")
  529.                             include = False
  530.  
  531.                         elif int(mq.get('support-type', SUPPORT_TYPE_NONE)) == SUPPORT_TYPE_NONE:
  532.                             log.debug("Not supported.")
  533.                             include = False
  534.  
  535.                         elif filter not in (None, 'print', 'print-type'):
  536.                             include = __checkFilter(filter, mq)
  537.  
  538.                         if include:
  539.                             ret_devices[uri] = (mdl, desc, devid) # model w/ _'s, mdl w/o
  540.  
  541.         elif b == 'cups':
  542.             cups_printers = cups.getPrinters()
  543.             x = len(cups_printers)
  544.  
  545.             for p in cups_printers:
  546.                 device_uri = p.device_uri
  547.                 log.debug("%s: %s" % (device_uri, p.name))
  548.  
  549.                 if device_uri != '':
  550.                     try:
  551.                         back_end, is_hp, bs, model, serial, dev_file, host, port = \
  552.                             parseDeviceURI(device_uri)
  553.                     except Error:
  554.                         log.debug("Unrecognized URI: %s" % device_uri)
  555.                         continue
  556.  
  557.                     if not is_hp:
  558.                         continue
  559.  
  560.                     include = True
  561.                     mq = queryModelByModel(model)
  562.  
  563.                     if not mq:
  564.                         include = False
  565.                         log.debug("Not found.")
  566.  
  567.                     elif int(mq.get('support-type', SUPPORT_TYPE_NONE)) == SUPPORT_TYPE_NONE:
  568.                         log.debug("Not supported.")
  569.                         include = False
  570.  
  571.                     elif filter not in (None, 'print', 'print-type'):
  572.                         include = __checkFilter(filter, mq)
  573.  
  574.                     if include:
  575.                         ret_devices[device_uri] = (model, model, '')
  576.  
  577.     probed_devices = {}
  578.     for uri in ret_devices:
  579.         num_devices += 1
  580.         mdl, model, devid_or_hn = ret_devices[uri]
  581.  
  582.         include = True
  583.         if search:
  584.             match_obj = search_pat.search("%s %s %s %s" % (mdl, model, devid_or_hn, uri))
  585.  
  586.             if match_obj is None:
  587.                 log.debug("%s %s %s %s: Does not match search '%s'." % (mdl, model, devid_or_hn, uri, search))
  588.                 include = False
  589.  
  590.         if include:
  591.             probed_devices[uri] = ret_devices[uri]
  592.  
  593.     cleanup_spinner()
  594.     return probed_devices
  595.  
  596. #
  597. # CUPS Devices
  598. #
  599.  
  600. def getSupportedCUPSDevices(back_end_filter=['hp'], filter=DEFAULT_FILTER):
  601.     devices = {}
  602.     printers = cups.getPrinters()
  603.  
  604.     for p in printers:
  605.         try:
  606.             back_end, is_hp, bus, model, serial, dev_file, host, port = \
  607.                 parseDeviceURI(p.device_uri)
  608.  
  609.         except Error:
  610.             continue
  611.  
  612.         if (back_end_filter == '*' or back_end in back_end_filter or \
  613.             ('hpaio' in back_end_filter and back_end == 'hp')) and \
  614.             model and is_hp:
  615.  
  616.             include = True
  617.             mq = queryModelByModel(model)
  618.  
  619.             if not mq:
  620.                 log.debug("Not found.")
  621.                 include = False
  622.  
  623.             elif int(mq.get('support-type', SUPPORT_TYPE_NONE)) == SUPPORT_TYPE_NONE:
  624.                 log.debug("Not supported.")
  625.                 include = False
  626.  
  627.             elif filter not in (None, 'print', 'print-type'):
  628.                 include = __checkFilter(filter, mq)
  629.  
  630.             if include:
  631.                 if 'hpaio' in back_end_filter:
  632.                     d = p.device_uri.replace('hp:', 'hpaio:')
  633.                 else:
  634.                     d = p.device_uri
  635.  
  636.                 try:
  637.                     devices[d]
  638.                 except KeyError:
  639.                     devices[d] = [p.name]
  640.                 else:
  641.                     devices[d].append(p.name)
  642.  
  643.     return devices # { 'device_uri' : [ CUPS printer list ], ... }
  644.  
  645.  
  646. def getSupportedCUPSPrinters(back_end_filter=['hp'], filter=DEFAULT_FILTER):
  647.     printer_list = []
  648.     printers = cups.getPrinters()
  649.  
  650.     for p in printers:
  651.         try:
  652.             back_end, is_hp, bus, model, serial, dev_file, host, port = \
  653.                 parseDeviceURI(p.device_uri)
  654.  
  655.         except Error:
  656.             continue
  657.  
  658.         if (back_end_filter == '*' or back_end in back_end_filter) and model and is_hp:
  659.             include = True
  660.             mq = queryModelByModel(model)
  661.  
  662.             if not mq:
  663.                 log.debug("Not found.")
  664.                 include = False
  665.  
  666.             elif int(mq.get('support-type', SUPPORT_TYPE_NONE)) == SUPPORT_TYPE_NONE:
  667.                 log.debug("Not supported.")
  668.                 include = False
  669.  
  670.             elif filter not in (None, 'print', 'print-type'):
  671.                 include = __checkFilter(filter, mq)
  672.  
  673.             if include:
  674.                 p.name = p.name.decode('utf-8')
  675.                 printer_list.append(p)
  676.             #printer_list[p.name] = p.device_uri
  677.  
  678.     return printer_list # [ cupsext.Printer, ... ]
  679.  
  680.  
  681. def getSupportedCUPSPrinterNames(back_end_filter=['hp'], filter=DEFAULT_FILTER):
  682.     printers = getSupportedCUPSPrinters(back_end_filter, filter)
  683.     return [p.name for p in printers]
  684.  
  685.  
  686. def getDeviceURIByPrinterName(printer_name, scan_uri_flag=False):
  687.     if printer_name is None:
  688.         return None
  689.  
  690.     device_uri = None
  691.     printers = cups.getPrinters()
  692.  
  693.     for p in printers:
  694.         try:
  695.             back_end, is_hp, bus, model, serial, dev_file, host, port = \
  696.                 parseDeviceURI(p.device_uri)
  697.  
  698.         except Error:
  699.             continue
  700.  
  701.         if is_hp and p.name == printer_name:
  702.             if scan_uri_flag:
  703.                 device_uri = p.device_uri.replace('hp:', 'hpaio:')
  704.             else:
  705.                 device_uri = p.device_uri
  706.             break
  707.  
  708.     return device_uri
  709.  
  710. #
  711. # IEEE-1284 Device ID parsing
  712. #
  713.  
  714. def parseDeviceID(device_id):
  715.     d= {}
  716.     x = [y.strip() for y in device_id.strip().split(';') if y]
  717.  
  718.     for z in x:
  719.         y = z.split(':')
  720.         try:
  721.             d.setdefault(y[0].strip(), y[1])
  722.         except IndexError:
  723.             d.setdefault(y[0].strip(), None)
  724.  
  725.     d.setdefault('MDL', '')
  726.     d.setdefault('SN',  '')
  727.  
  728.     if 'MODEL' in d:
  729.         d['MDL'] = d['MODEL']
  730.         del d['MODEL']
  731.  
  732.     if 'SERIAL' in d:
  733.         d['SN'] = d['SERIAL']
  734.         del d['SERIAL']
  735.  
  736.     elif 'SERN' in d:
  737.         d['SN'] = d['SERN']
  738.         del d['SERN']
  739.  
  740.     if d['SN'].startswith('X'):
  741.         d['SN'] = ''
  742.  
  743.     return d
  744.  
  745. #
  746. # IEEE-1284 Device ID Dynamic Counter Parsing
  747. #
  748.  
  749. def parseDynamicCounter(ctr_field, convert_to_int=True):
  750.     counter, value = ctr_field.split(' ')
  751.     try:
  752.         counter = int(utils.xlstrip(str(counter), '0') or '0')
  753.  
  754.         if convert_to_int:
  755.             value = int(utils.xlstrip(str(value), '0') or '0')
  756.     except ValueError:
  757.         if convert_to_int:
  758.             counter, value = 0, 0
  759.         else:
  760.             counter, value = 0, ''
  761.  
  762.     return counter, value
  763.  
  764.  
  765. #
  766. # Parse Device URI Strings
  767. #
  768.  
  769. def parseDeviceURI(device_uri):
  770.     m = pat_deviceuri.match(device_uri)
  771.  
  772.     if m is None:
  773.         log.debug("Device URI %s is invalid/unknown" % device_uri)
  774.         raise Error(ERROR_INVALID_DEVICE_URI)
  775.  
  776.     back_end = m.group(1).lower() or ''
  777.     is_hp = (back_end in ('hp', 'hpfax', 'hpaio'))
  778.     bus = m.group(2).lower() or ''
  779.  
  780.     if bus not in ('usb', 'net', 'bt', 'fw', 'par'):
  781.         log.debug("Device URI %s is invalid/unknown" % device_uri)
  782.         raise Error(ERROR_INVALID_DEVICE_URI)
  783.  
  784.     model = m.group(3) or ''
  785.     serial = m.group(4) or ''
  786.     dev_file = m.group(5) or ''
  787.     host = m.group(6) or ''
  788.     port = m.group(7) or 1
  789.  
  790.     if bus == 'net':
  791.         try:
  792.             port = int(port)
  793.         except (ValueError, TypeError):
  794.             port = 1
  795.  
  796.         if port == 0:
  797.             port = 1
  798.  
  799.     return back_end, is_hp, bus, model, serial, dev_file, host, port
  800.  
  801.  
  802. def isLocal(bus):
  803.     return bus in ('par', 'usb', 'fw', 'bt')
  804.  
  805.  
  806. def isNetwork(bus):
  807.     return bus in ('net',)
  808.  
  809.  
  810. #
  811. # Misc
  812. #
  813.  
  814. def __checkFilter(filter, mq):
  815.     for f, p in filter.items():
  816.         if f is not None:
  817.             op, val = p
  818.             if not op(mq[f], val):
  819.                 return False
  820.  
  821.     return True
  822.  
  823.  
  824. def validateBusList(bus, allow_cups=True):
  825.     for b in bus:
  826.         if allow_cups:
  827.             vb = VALID_BUSES
  828.         else:
  829.             vb = VALID_BUSES_WO_CUPS
  830.  
  831.         if b not in vb:
  832.             log.error("Invalid bus name: %s" %b)
  833.             return False
  834.  
  835.     return True
  836.  
  837.  
  838. def validateFilterList(filter):
  839.     if filter is None:
  840.         return True
  841.  
  842.     for f in filter:
  843.         if f not in VALID_FILTERS:
  844.             log.error("Invalid term '%s' in filter list" % f)
  845.             return False
  846.  
  847.     return True
  848.  
  849.  
  850. #
  851. # UI String Queries (why is this here?)
  852. #
  853.  
  854. inter_pat = re.compile(r"""%(.*)%""", re.IGNORECASE)
  855. st = StringTable()
  856. strings_init = False
  857.  
  858.  
  859. def initStrings():
  860.     global strings_init, st
  861.     strings_init = True
  862.     cycles = 0
  863.  
  864.     while True:
  865.         found = False
  866.  
  867.         for s in st.string_table:
  868.             short_string, long_string = st.string_table[s]
  869.             short_replace, long_replace = short_string, long_string
  870.  
  871.             try:
  872.                 short_match = inter_pat.match(short_string).group(1)
  873.             except (AttributeError, TypeError):
  874.                 short_match = None
  875.  
  876.             if short_match is not None:
  877.                 found = True
  878.  
  879.                 try:
  880.                     short_replace, dummy = st.string_table[short_match]
  881.                 except KeyError:
  882.                     log.error("String interpolation error: %s" % short_match)
  883.  
  884.             try:
  885.                 long_match = inter_pat.match(long_string).group(1)
  886.             except (AttributeError, TypeError):
  887.                 long_match = None
  888.  
  889.             if long_match is not None:
  890.                 found = True
  891.  
  892.                 try:
  893.                     dummy, long_replace = st.string_table[long_match]
  894.                 except KeyError:
  895.                     log.error("String interpolation error: %s" % long_match)
  896.  
  897.             if found:
  898.                 st.string_table[s] = (short_replace, long_replace)
  899.  
  900.         if not found:
  901.             break
  902.         else:
  903.             cycles +=1
  904.             if cycles > 1000:
  905.                 break
  906.  
  907.  
  908. def queryString(string_id, typ=0):
  909.     if not strings_init:
  910.         initStrings()
  911.  
  912.     #log.debug("queryString(%s)" % string_id)
  913.     s = st.string_table.get(str(string_id), ('', ''))[typ]
  914.  
  915.     if type(s) == type(''):
  916.         return s
  917.  
  918.     return s()
  919.  
  920.  
  921. AGENT_types = { AGENT_TYPE_NONE        : 'invalid',
  922.                 AGENT_TYPE_BLACK       : 'black',
  923.                 AGENT_TYPE_CMY         : 'cmy',
  924.                 AGENT_TYPE_KCM         : 'kcm',
  925.                 AGENT_TYPE_CYAN        : 'cyan',
  926.                 AGENT_TYPE_MAGENTA     : 'magenta',
  927.                 AGENT_TYPE_YELLOW      : 'yellow',
  928.                 AGENT_TYPE_CYAN_LOW    : 'photo_cyan',
  929.                 AGENT_TYPE_MAGENTA_LOW : 'photo_magenta',
  930.                 AGENT_TYPE_YELLOW_LOW  : 'photo_yellow',
  931.                 AGENT_TYPE_GGK         : 'photo_gray',
  932.                 AGENT_TYPE_BLUE        : 'photo_blue',
  933.                 AGENT_TYPE_KCMY_CM     : 'kcmy_cm',
  934.                 AGENT_TYPE_LC_LM       : 'photo_cyan_and_photo_magenta',
  935.                 #AGENT_TYPE_Y_M         : 'yellow_and_magenta',
  936.                 #AGENT_TYPE_C_K         : 'cyan_and_black',
  937.                 AGENT_TYPE_LG_PK       : 'light_gray_and_photo_black',
  938.                 AGENT_TYPE_LG          : 'light_gray',
  939.                 AGENT_TYPE_G           : 'medium_gray',
  940.                 AGENT_TYPE_PG          : 'photo_gray',
  941.                 AGENT_TYPE_C_M         : 'cyan_and_magenta',
  942.                 AGENT_TYPE_K_Y         : 'black_and_yellow',
  943.                 AGENT_TYPE_UNSPECIFIED : 'unspecified', # Kind=5,6
  944.             }
  945.  
  946. AGENT_kinds = {AGENT_KIND_NONE            : 'invalid',
  947.                 AGENT_KIND_HEAD            : 'head',
  948.                 AGENT_KIND_SUPPLY          : 'supply',
  949.                 AGENT_KIND_HEAD_AND_SUPPLY : 'cartridge',
  950.                 AGENT_KIND_TONER_CARTRIDGE : 'toner',
  951.                 AGENT_KIND_MAINT_KIT       : 'maint_kit', # fuser
  952.                 AGENT_KIND_ADF_KIT         : 'adf_kit',
  953.                 AGENT_KIND_DRUM_KIT        : 'drum_kit',
  954.                 AGENT_KIND_TRANSFER_KIT    : 'transfer_kit',
  955.                 AGENT_KIND_INT_BATTERY     : 'battery',
  956.                 AGENT_KIND_UNKNOWN         : 'unknown',
  957.               }
  958.  
  959. AGENT_healths = {AGENT_HEALTH_OK           : 'ok',
  960.                   AGENT_HEALTH_MISINSTALLED : 'misinstalled', # supply/cart
  961.                   #AGENT_HEALTH_FAIR_MODERATE : '',
  962.                   AGENT_HEALTH_INCORRECT    : 'incorrect',
  963.                   AGENT_HEALTH_FAILED       : 'failed',
  964.                   AGENT_HEALTH_OVERTEMP     : 'overtemp', # battery
  965.                   AGENT_HEALTH_CHARGING     : 'charging', # battery
  966.                   AGENT_HEALTH_DISCHARGING  : 'discharging', # battery
  967.                 }
  968.  
  969.  
  970. AGENT_levels = {AGENT_LEVEL_TRIGGER_MAY_BE_LOW : 'low',
  971.                  AGENT_LEVEL_TRIGGER_PROBABLY_OUT : 'low',
  972.                  AGENT_LEVEL_TRIGGER_ALMOST_DEFINITELY_OUT : 'out',
  973.                }
  974.  
  975.  
  976. #
  977.  
  978.  
  979.  
  980. # **************************************************************************** #
  981.  
  982. string_cache = {}
  983.  
  984. class Device(object):
  985.     def __init__(self, device_uri, printer_name=None,
  986.                  service=None, callback=None, disable_dbus=False):
  987.  
  988.         log.debug("Device URI: %s" % device_uri)
  989.         log.debug("Printer: %s" % printer_name)
  990.  
  991.         global dbus_disabled
  992.         dbus_disabled = disable_dbus
  993.  
  994.         if not disable_dbus:
  995.             if service is None:
  996.                 self.dbus_avail, self.service,  session_bus = init_dbus()
  997.             else:
  998.                 self.dbus_avail = True
  999.                 self.service = service
  1000.         else:
  1001.             self.dbus_avail = False
  1002.             self.service = None
  1003.  
  1004.         self.last_event = None # Used in devmgr if dbus is disabled
  1005.  
  1006.         printers = cups.getPrinters()
  1007.  
  1008.         if device_uri is None and printer_name is not None:
  1009.             for p in printers:
  1010.                 if p.name.lower() == printer_name.lower():
  1011.                     device_uri = p.device_uri
  1012.                     log.debug("Device URI: %s" % device_uri)
  1013.                     break
  1014.             else:
  1015.                 raise Error(ERROR_DEVICE_NOT_FOUND)
  1016.  
  1017.         self.device_uri = device_uri
  1018.         self.callback = callback
  1019.         self.device_type = DEVICE_TYPE_UNKNOWN
  1020.  
  1021.         if self.device_uri is None:
  1022.             raise Error(ERROR_DEVICE_NOT_FOUND)
  1023.  
  1024.         if self.device_uri.startswith('hp:'):
  1025.             self.device_type = DEVICE_TYPE_PRINTER
  1026.  
  1027.         elif self.device_uri.startswith('hpaio:'):
  1028.             self.device_type = DEVICE_TYPE_SCANNER
  1029.  
  1030.         elif self.device_uri.startswith('hpfax:'):
  1031.             self.device_type = DEVICE_TYPE_FAX
  1032.  
  1033.         try:
  1034.             self.back_end, self.is_hp, self.bus, self.model, \
  1035.                 self.serial, self.dev_file, self.host, self.port = \
  1036.                 parseDeviceURI(self.device_uri)
  1037.         except Error:
  1038.             self.io_state = IO_STATE_NON_HP
  1039.             raise Error(ERROR_INVALID_DEVICE_URI)
  1040.  
  1041.         log.debug("URI: backend=%s, is_hp=%s, bus=%s, model=%s, serial=%s, dev=%s, host=%s, port=%d" % \
  1042.             (self.back_end, self.is_hp, self.bus, self.model, self.serial, self.dev_file, self.host, self.port))
  1043.  
  1044.         self.model_ui = models.normalizeModelUIName(self.model)
  1045.         self.model = models.normalizeModelName(self.model)
  1046.  
  1047.         log.debug("Model/UI model: %s/%s" % (self.model, self.model_ui))
  1048.  
  1049.         # TODO:
  1050.         #service.setAlertsEx(self.hpssd_sock)
  1051.  
  1052.         self.mq = {} # Model query
  1053.         self.dq = {} # Device query
  1054.         self.icon = "default_printer"
  1055.         self.cups_printers = []
  1056.         self.channels = {} # { 'SERVICENAME' : channel_id, ... }
  1057.         self.device_id = -1
  1058.         self.r_values = None # ( r_value, r_value_str, rg, rr )
  1059.         self.deviceID = ''
  1060.         self.panel_check = True
  1061.         self.io_state = IO_STATE_HP_READY
  1062.         self.is_local = isLocal(self.bus)
  1063.         self.hist = []
  1064.  
  1065.         self.supported = False
  1066.  
  1067.         self.queryModel()
  1068.         if not self.supported:
  1069.             log.error("Unsupported model: %s" % self.model)
  1070.             self.error_code = STATUS_DEVICE_UNSUPPORTED
  1071.             self.sendEvent(self.error_code)
  1072.         else:
  1073.             self.supported = True
  1074.  
  1075.  
  1076.         self.mq.update({'model'    : self.model,
  1077.                         'model-ui' : self.model_ui})
  1078.  
  1079.         self.error_state = ERROR_STATE_ERROR
  1080.         self.device_state = DEVICE_STATE_NOT_FOUND
  1081.         self.status_code = EVENT_ERROR_DEVICE_NOT_FOUND
  1082.  
  1083.         for p in printers:
  1084.             if self.device_uri == p.device_uri:
  1085.                 self.cups_printers.append(p.name)
  1086.                 self.state = p.state # ?
  1087.  
  1088.                 if self.io_state == IO_STATE_NON_HP:
  1089.                     self.model = p.makemodel.split(',')[0]
  1090.  
  1091.         try:
  1092.             self.first_cups_printer = self.cups_printers[0]
  1093.         except IndexError:
  1094.             self.first_cups_printer = ''
  1095.  
  1096.         if self.mq.get('fax-type', FAX_TYPE_NONE) != FAX_TYPE_NONE:
  1097.             self.dq.update({ 'fax-uri' : self.device_uri.replace('hp:/', 'hpfax:/').replace('hpaio:/', 'hpfax:/')})
  1098.  
  1099.         if self.mq.get('scan-type', SCAN_TYPE_NONE) != SCAN_TYPE_NONE:
  1100.             self.dq.update({ 'scan-uri' : self.device_uri.replace('hp:/', 'hpaio:/').replace('hpfax:/', 'hpaio:/')})
  1101.  
  1102.         self.dq.update({
  1103.             'back-end'         : self.back_end,
  1104.             'is-hp'            : self.is_hp,
  1105.             'serial'           : self.serial,
  1106.             'dev-file'         : self.dev_file,
  1107.             'host'             : self.host,
  1108.             'port'             : self.port,
  1109.             'cups-printer'     : ','.join(self.cups_printers),
  1110.             'status-code'      : self.status_code,
  1111.             'status-desc'      : '',
  1112.             'deviceid'         : '',
  1113.             'panel'            : 0,
  1114.             'panel-line1'      : '',
  1115.             'panel-line2'      : '',
  1116.             'device-state'     : self.device_state,
  1117.             'error-state'      : self.error_state,
  1118.             'device-uri'       : self.device_uri,
  1119.             'cups-uri'         : self.device_uri.replace('hpfax:/', 'hp:/').replace('hpaio:/', 'hp:/'),
  1120.             })
  1121.  
  1122.         self.device_vars = {
  1123.             'URI'        : self.device_uri,
  1124.             'DEVICE_URI' : self.device_uri,
  1125.             'SCAN_URI'   : self.device_uri.replace('hp:', 'hpaio:'),
  1126.             'SANE_URI'   : self.device_uri.replace('hp:', 'hpaio:'),
  1127.             'FAX_URI'    : self.device_uri.replace('hp:', 'hpfax:'),
  1128.             'PRINTER'    : self.first_cups_printer,
  1129.             'HOME'       : prop.home_dir,
  1130.                            }
  1131.  
  1132.  
  1133.  
  1134.  
  1135.     def sendEvent(self, event_code, printer_name='', job_id=0, title=''):
  1136.         if self.dbus_avail and self.service is not None:
  1137.             try:
  1138.                 log.debug("Sending event %d to hpssd..." % event_code)
  1139.                 self.service.SendEvent(self.device_uri, printer_name, event_code, prop.username, job_id, title)
  1140.             except dbus.exceptions.DBusException, e:
  1141.                 log.debug("dbus call to SendEvent() failed.")
  1142.  
  1143.  
  1144.     def quit(self):
  1145.         pass
  1146.  
  1147.  
  1148.     def queryModel(self):
  1149.         if not self.mq:
  1150.             self.mq = queryModelByURI(self.device_uri)
  1151.  
  1152.         self.supported = bool(self.mq)
  1153.  
  1154.         if self.supported:
  1155.             for m in self.mq:
  1156.                 self.__dict__[m.replace('-','_')] = self.mq[m]
  1157.  
  1158.  
  1159.     def queryString(self, string_id):
  1160.         return queryString(string_id)
  1161.  
  1162.  
  1163.     def open(self, open_for_printing=False):
  1164. #       print "open()"
  1165. #       raise Error(ERROR_DEVICE_NOT_FOUND)
  1166. #       return
  1167.  
  1168.         if self.supported and self.io_state in (IO_STATE_HP_READY, IO_STATE_HP_NOT_AVAIL):
  1169.             prev_device_state = self.device_state
  1170.             self.io_state = IO_STATE_HP_NOT_AVAIL
  1171.             self.device_state = DEVICE_STATE_NOT_FOUND
  1172.             self.error_state = ERROR_STATE_ERROR
  1173.             self.status_code = EVENT_ERROR_DEVICE_NOT_FOUND
  1174.             self.device_id = -1
  1175.             self.open_for_printing = open_for_printing
  1176.  
  1177.             if open_for_printing:
  1178.                 log.debug("Opening device: %s (for printing)" % self.device_uri)
  1179.                 self.io_mode = self.mq.get('io-mode', hpmudext.HPMUD_UNI_MODE)
  1180.             else:
  1181.                 log.debug("Opening device: %s (not for printing)" % self.device_uri)
  1182.                 self.io_mode = self.mq.get('io-mfp-mode', hpmudext.HPMUD_UNI_MODE)
  1183.  
  1184.             log.debug("I/O mode=%d" % self.io_mode)
  1185.             result_code, self.device_id = \
  1186.                 hpmudext.open_device(self.device_uri, self.io_mode)
  1187.  
  1188.             if result_code != hpmudext.HPMUD_R_OK:
  1189.                 self.error_state = ERROR_STATE_ERROR
  1190.                 self.error_code = result_code+ERROR_CODE_BASE
  1191.                 self.sendEvent(self.error_code)
  1192.  
  1193.                 if result_code == hpmudext.HPMUD_R_DEVICE_BUSY:
  1194.                     log.error("Device busy: %s" % self.device_uri)
  1195.                 else:
  1196.                     log.error("Unable to communicate with device (code=%d): %s" % (result_code, self.device_uri))
  1197.  
  1198.                 self.last_event = Event(self.device_uri, '', EVENT_ERROR_DEVICE_NOT_FOUND,
  1199.                         prop.username, 0, '', time.time())
  1200.  
  1201.                 raise Error(ERROR_DEVICE_NOT_FOUND)
  1202.  
  1203.             else:
  1204.                 log.debug("device-id=%d" % self.device_id)
  1205.                 self.io_state = IO_STATE_HP_OPEN
  1206.                 self.error_state = ERROR_STATE_CLEAR
  1207.                 log.debug("Opened device: %s (backend=%s, is_hp=%s, bus=%s, model=%s, dev=%s, serial=%s, host=%s, port=%d)" %
  1208.                     (self.back_end, self.device_uri, self.is_hp, self.bus, self.model,
  1209.                      self.dev_file, self.serial, self.host, self.port))
  1210.  
  1211.                 if prev_device_state == DEVICE_STATE_NOT_FOUND:
  1212.                     self.device_state = DEVICE_STATE_JUST_FOUND
  1213.                 else:
  1214.                     self.device_state = DEVICE_STATE_FOUND
  1215.  
  1216.                 self.getDeviceID()
  1217.                 self.getSerialNumber()
  1218.                 return self.device_id
  1219.  
  1220.  
  1221.     def close(self):
  1222.         if self.io_state == IO_STATE_HP_OPEN:
  1223.             log.debug("Closing device...")
  1224.  
  1225.             if len(self.channels) > 0:
  1226.  
  1227.                 for c in self.channels.keys():
  1228.                     self.__closeChannel(c)
  1229.  
  1230.             result_code = hpmudext.close_device(self.device_id)
  1231.             log.debug("Result-code = %d" % result_code)
  1232.  
  1233.             self.channels.clear()
  1234.             self.io_state = IO_STATE_HP_READY
  1235.  
  1236.  
  1237.     def __openChannel(self, service_name):
  1238.         try:
  1239.             if self.io_state == IO_STATE_HP_OPEN:
  1240.                 if service_name == hpmudext.HPMUD_S_PRINT_CHANNEL and not self.open_for_printing:
  1241.                     self.close()
  1242.                     self.open(True)
  1243.                 elif service_name != hpmudext.HPMUD_S_PRINT_CHANNEL and self.open_for_printing:
  1244.                     self.close()
  1245.                     self.open(False)
  1246.             else:
  1247.                 self.open(service_name == hpmudext.HPMUD_S_PRINT_CHANNEL)
  1248.         except:
  1249.             log.error("unable to open channel")
  1250.             return -1
  1251.  
  1252.         #if not self.mq['io-mode'] == IO_MODE_UNI:
  1253.         if 1:
  1254.             service_name = service_name.upper()
  1255.  
  1256.             if service_name not in self.channels:
  1257.                 log.debug("Opening %s channel..." % service_name)
  1258.  
  1259.                 result_code, channel_id = hpmudext.open_channel(self.device_id, service_name)
  1260.  
  1261.                 self.channels[service_name] = channel_id
  1262.                 log.debug("channel-id=%d" % channel_id)
  1263.                 return channel_id
  1264.             else:
  1265.                 return self.channels[service_name]
  1266.         else:
  1267.             return -1
  1268.  
  1269.  
  1270.     def openChannel(self, service_name):
  1271.         return self.__openChannel(service_name)
  1272.  
  1273.     def openPrint(self):
  1274.         return self.__openChannel(hpmudext.HPMUD_S_PRINT_CHANNEL)
  1275.  
  1276.     def openFax(self):
  1277.         return self.__openChannel(hpmudext.HPMUD_S_FAX_SEND_CHANNEL)
  1278.  
  1279.     def openPCard(self):
  1280.         return self.__openChannel(hpmudext.HPMUD_S_MEMORY_CARD_CHANNEL)
  1281.  
  1282.     def openEWS(self):
  1283.         return self.__openChannel(hpmudext.HPMUD_S_EWS_CHANNEL)
  1284.  
  1285.     def closePrint(self):
  1286.         return self.__closeChannel(hpmudext.HPMUD_S_PRINT_CHANNEL)
  1287.  
  1288.     def closePCard(self):
  1289.         return self.__closeChannel(hpmudext.HPMUD_S_MEMORY_CARD_CHANNEL)
  1290.  
  1291.     def closeFax(self):
  1292.         return self.__closeChannel(hpmudext.HPMUD_S_FAX_SEND_CHANNEL)
  1293.  
  1294.     def openPML(self):
  1295.         return self.__openChannel(hpmudext.HPMUD_S_PML_CHANNEL)
  1296.  
  1297.     def closePML(self):
  1298.         return self.__closeChannel(hpmudext.HPMUD_S_PML_CHANNEL)
  1299.  
  1300.     def closeEWS(self):
  1301.         return self.__closeChannel(hpmudext.HPMUD_S_EWS_CHANNEL)
  1302.  
  1303.     def openCfgUpload(self):
  1304.         return self.__openChannel(hpmudext.HPMUD_S_CONFIG_UPLOAD_CHANNEL)
  1305.  
  1306.     def closeCfgUpload(self):
  1307.         return self.__closeChannel(hpmudext.HPMUD_S_CONFIG_UPLOAD_CHANNEL)
  1308.  
  1309.     def openCfgDownload(self):
  1310.         return self.__openChannel(hpmudext.HPMUD_S_CONFIG_DOWNLOAD_CHANNEL)
  1311.  
  1312.     def closeCfgDownload(self):
  1313.         return self.__closeChannel(hpmudext.HPMUD_S_CONFIG_DOWNLOAD_CHANNEL)
  1314.  
  1315.     def openSoapFax(self):
  1316.         return self.__openChannel(hpmudext.HPMUD_S_SOAP_FAX)
  1317.  
  1318.     def closeSoapFax(self):
  1319.         return self.__closeChannel(hpmudext.HPMUD_S_SOAP_FAX)
  1320.  
  1321.     def __closeChannel(self, service_name):
  1322.         #if not self.mq['io-mode'] == IO_MODE_UNI and \
  1323.         if self.io_state == IO_STATE_HP_OPEN:
  1324.  
  1325.             service_name = service_name.upper()
  1326.  
  1327.             if service_name in self.channels:
  1328.                 log.debug("Closing %s channel..." % service_name)
  1329.  
  1330.                 result_code = hpmudext.close_channel(self.device_id,
  1331.                     self.channels[service_name])
  1332.  
  1333.                 del self.channels[service_name]
  1334.  
  1335.  
  1336.     def closeChannel(self, service_name):
  1337.         return self.__closeChannel(service_name)
  1338.  
  1339.  
  1340.     def getDeviceID(self):
  1341.         needs_close = False
  1342.         if self.io_state != IO_STATE_HP_OPEN:
  1343.            try:
  1344.                self.open()
  1345.            except:
  1346.                return -1
  1347.            needs_close = True
  1348.  
  1349.         result_code, data = hpmudext.get_device_id(self.device_id)
  1350.  
  1351.         if result_code != hpmudext.HPMUD_R_OK:
  1352.             self.raw_deviceID = ''
  1353.             self.deviceID = {}
  1354.         else:
  1355.             self.raw_deviceID = data
  1356.             self.deviceID = parseDeviceID(data)
  1357.  
  1358.         if needs_close:
  1359.             self.close()
  1360.  
  1361.         return self.deviceID
  1362.  
  1363.  
  1364.     def getSerialNumber(self):
  1365.         if self.serial:
  1366.             return
  1367.  
  1368.         try:
  1369.             self.serial = self.deviceID['SN']
  1370.         except KeyError:
  1371.             pass
  1372.         else:
  1373.             if self.serial:
  1374.                 return
  1375.  
  1376.         if self.mq.get('status-type', STATUS_TYPE_NONE) != STATUS_TYPE_NONE: # and \
  1377.             #not self.mq.get('io-mode', IO_MODE_UNI) == IO_MODE_UNI:
  1378.  
  1379.             try:
  1380.                 try:
  1381.                     error_code, self.serial = self.getPML(pml.OID_SERIAL_NUMBER)
  1382.                 except Error:
  1383.                     self.serial = ''
  1384.             finally:
  1385.                 self.closePML()
  1386.  
  1387.         if self.serial is None:
  1388.             self.serial = ''
  1389.  
  1390.  
  1391.     def getThreeBitStatus(self):
  1392.         pass
  1393.  
  1394.  
  1395.     def getStatusFromDeviceID(self):
  1396.         self.getDeviceID()
  1397.         return status.parseStatus(parseDeviceID(self.raw_deviceID))
  1398.  
  1399.  
  1400.     def __parseRValues(self, r_value):
  1401.         r_value_str = str(r_value)
  1402.         r_value_str = ''.join(['0'*(9 - len(r_value_str)), r_value_str])
  1403.         rg, rr = r_value_str[:3], r_value_str[3:]
  1404.         r_value = int(rr)
  1405.         self.r_values = r_value, r_value_str, rg, rr
  1406.         return r_value, r_value_str, rg, rr
  1407.  
  1408.  
  1409.     def getRValues(self, r_type, status_type, dynamic_counters):
  1410.         r_value, r_value_str, rg, rr = 0, '000000000', '000', '000000'
  1411.  
  1412.         if r_type > 0 and \
  1413.             dynamic_counters != STATUS_DYNAMIC_COUNTERS_NONE:
  1414.  
  1415.             if self.r_values is None:
  1416.                 if self.dbus_avail:
  1417.                     try:
  1418.                         r_value = int(self.service.GetCachedIntValue(self.device_uri, 'r_value'))
  1419.                     except dbus.exceptions.DBusException, e:
  1420.                         log.debug("dbus call to GetCachedIntValue() failed.")
  1421.                         r_value = -1
  1422.  
  1423.                 if r_value != -1:
  1424.                     log.debug("r_value=%d" % r_value)
  1425.                     r_value, r_value_str, rg, rr = self.__parseRValues(r_value)
  1426.  
  1427.                     return r_value, r_value_str, rg, rr
  1428.  
  1429.             if self.r_values is None:
  1430.  
  1431.                 if status_type ==  STATUS_TYPE_S and \
  1432.                     self.is_local and \
  1433.                     dynamic_counters != STATUS_DYNAMIC_COUNTERS_PML_SNMP:
  1434.  
  1435.                     try:
  1436.                         try:
  1437.                             r_value = self.getDynamicCounter(140)
  1438.  
  1439.                             if r_value is not None:
  1440.                                 log.debug("r_value=%d" % r_value)
  1441.                                 r_value, r_value_str, rg, rr = self.__parseRValues(r_value)
  1442.  
  1443.                                 if self.dbus_avail:
  1444.                                     try:
  1445.                                         self.service.SetCachedIntValue(self.device_uri, 'r_value', r_value)
  1446.                                     except dbus.exceptions.DBusException, e:
  1447.                                         log.debug("dbus call to SetCachedIntValue() failed.")
  1448.                             else:
  1449.                                 log.error("Error attempting to read r-value (2).")
  1450.                                 r_value = 0
  1451.                         except Error:
  1452.                             log.error("Error attempting to read r-value (1).")
  1453.                             r_value = 0
  1454.                     finally:
  1455.                         self.closePrint()
  1456.  
  1457.  
  1458.                 elif (status_type ==  STATUS_TYPE_S and
  1459.                       dynamic_counters == STATUS_DYNAMIC_COUNTERS_PCL and
  1460.                       not self.is_local) or \
  1461.                       dynamic_counters == STATUS_DYNAMIC_COUNTERS_PML_SNMP:
  1462.  
  1463.                     try:
  1464.                         result_code, r_value = self.getPML(pml.OID_R_SETTING)
  1465.  
  1466.                         if r_value is not None:
  1467.                             log.debug("r_value=%d" % r_value)
  1468.                             r_value, r_value_str, rg, rr = self.__parseRValues(r_value)
  1469.  
  1470.                             if self.dbus_avail:
  1471.                                 try:
  1472.                                     self.service.SetCachedIntValue(self.device_uri, 'r_value', r_value)
  1473.                                 except dbus.exceptions.DBusException, e:
  1474.                                     log.debug("dbus call to SetCachedIntValue() failed.")
  1475.  
  1476.                         else:
  1477.                             r_value = 0
  1478.  
  1479.                     finally:
  1480.                         self.closePML()
  1481.  
  1482.             else:
  1483.                 r_value, r_value_str, rg, rr = self.r_values
  1484.  
  1485.         return r_value, r_value_str, rg, rr
  1486.  
  1487.  
  1488.     def __queryFax(self, quick=False, reread_cups_printers=False):
  1489. #       print "__queryFax()"
  1490. #       raise Error(ERROR_DEVICE_IO_ERROR)
  1491. #       return
  1492.  
  1493.         io_mode = self.mq.get('io-mode', IO_MODE_UNI)
  1494.         self.status_code = STATUS_PRINTER_IDLE
  1495.  
  1496.         if io_mode != IO_MODE_UNI:
  1497.  
  1498.             if self.device_state != DEVICE_STATE_NOT_FOUND:
  1499.                 if self.tech_type in (TECH_TYPE_MONO_INK, TECH_TYPE_COLOR_INK):
  1500.                     try:
  1501.                         self.getDeviceID()
  1502.                     except Error, e:
  1503.                         log.error("Error getting device ID.")
  1504.                         self.last_event = Event(self.device_uri, '', ERROR_DEVICE_IO_ERROR,
  1505.                             prop.username, 0, '', time.time())
  1506.  
  1507.                         raise Error(ERROR_DEVICE_IO_ERROR)
  1508.  
  1509.                 status_desc = self.queryString(self.status_code)
  1510.  
  1511.                 #print self.status_code
  1512.  
  1513.                 self.dq.update({
  1514.                     'serial'           : self.serial,
  1515.                     'cups-printer'     : ','.join(self.cups_printers),
  1516.                     'status-code'      : self.status_code,
  1517.                     'status-desc'      : status_desc,
  1518.                     'deviceid'         : self.raw_deviceID,
  1519.                     'panel'            : 0,
  1520.                     'panel-line1'      : '',
  1521.                     'panel-line2'      : '',
  1522.                     'device-state'     : self.device_state,
  1523.                     'error-state'      : self.error_state,
  1524.                     })
  1525.  
  1526.  
  1527.             log.debug("Fax activity check...")
  1528.  
  1529.             tx_active, rx_active = status.getFaxStatus(self)
  1530.  
  1531.             if tx_active:
  1532.                 self.status_code = STATUS_FAX_TX_ACTIVE
  1533.             elif rx_active:
  1534.                 self.status_code = STATUS_FAX_RX_ACTIVE
  1535.  
  1536.             #print self.status_code
  1537.  
  1538.             self.error_state = STATUS_TO_ERROR_STATE_MAP.get(self.status_code, ERROR_STATE_CLEAR)
  1539.             self.error_code = self.status_code
  1540.             self.sendEvent(self.error_code)
  1541.  
  1542.             #print "Error state=", self.error_state, self.device_uri
  1543.  
  1544.             try:
  1545.                 self.dq.update({'status-desc' : self.queryString(self.status_code),
  1546.                                 'error-state' : self.error_state,
  1547.                                 })
  1548.  
  1549.             except (KeyError, Error):
  1550.                 self.dq.update({'status-desc' : '',
  1551.                                 'error-state' : ERROR_STATE_CLEAR,
  1552.                                 })
  1553.  
  1554.  
  1555.             if self.panel_check:
  1556.                 self.panel_check = bool(self.mq.get('panel-check-type', 0))
  1557.  
  1558.             status_type = self.mq.get('status-type', STATUS_TYPE_NONE)
  1559.             if self.panel_check and \
  1560.                 status_type in (STATUS_TYPE_LJ, STATUS_TYPE_S, STATUS_TYPE_VSTATUS) and \
  1561.                 io_mode != IO_MODE_UNI:
  1562.  
  1563.                 log.debug("Panel check...")
  1564.                 try:
  1565.                     self.panel_check, line1, line2 = status.PanelCheck(self)
  1566.                 finally:
  1567.                     self.closePML()
  1568.  
  1569.                 self.dq.update({'panel': int(self.panel_check),
  1570.                                   'panel-line1': line1,
  1571.                                   'panel-line2': line2,})
  1572.  
  1573.             if not quick and reread_cups_printers:
  1574.                 self.cups_printers = []
  1575.                 log.debug("Re-reading CUPS printer queue information.")
  1576.                 printers = cups.getPrinters()
  1577.                 for p in printers:
  1578.                     if self.device_uri == p.device_uri:
  1579.                         self.cups_printers.append(p.name)
  1580.                         self.state = p.state # ?
  1581.  
  1582.                         if self.io_state == IO_STATE_NON_HP:
  1583.                             self.model = p.makemodel.split(',')[0]
  1584.  
  1585.                 self.dq.update({'cups-printer' : ','.join(self.cups_printers)})
  1586.  
  1587.                 try:
  1588.                     self.first_cups_printer = self.cups_printers[0]
  1589.                 except IndexError:
  1590.                     self.first_cups_printer = ''
  1591.  
  1592.  
  1593.         for d in self.dq:
  1594.             self.__dict__[d.replace('-','_')] = self.dq[d]
  1595.  
  1596.         self.last_event = Event(self.device_uri, '', self.status_code, prop.username, 0, '', time.time())
  1597.         #print self.last_event
  1598.  
  1599.         log.debug(self.dq)
  1600.  
  1601.         #import pprint
  1602.  
  1603.         #pprint.pprint(self.dq)
  1604.  
  1605.  
  1606.  
  1607.  
  1608.     def queryDevice(self, quick=False, reread_cups_printers=False):
  1609. #       print "queryDevice()"
  1610. #       raise Error(ERROR_DEVICE_IO_ERROR)
  1611. #       return
  1612.  
  1613.         if not self.supported:
  1614.             self.dq = {}
  1615.  
  1616.             self.last_event = Event(self.device_uri, '', STATUS_DEVICE_UNSUPPORTED,
  1617.                 prop.username, 0, '', time.time())
  1618.  
  1619.             return
  1620.  
  1621.         if self.device_type == DEVICE_TYPE_FAX:
  1622.             return self.__queryFax(quick, reread_cups_printers)
  1623.  
  1624.         r_type = self.mq.get('r-type', 0)
  1625.         tech_type = self.mq.get('tech-type', TECH_TYPE_NONE)
  1626.         status_type = self.mq.get('status-type', STATUS_TYPE_NONE)
  1627.         battery_check = self.mq.get('status-battery-check', STATUS_BATTERY_CHECK_NONE)
  1628.         dynamic_counters = self.mq.get('status-dynamic-counters', STATUS_DYNAMIC_COUNTERS_NONE)
  1629.         io_mode = self.mq.get('io-mode', IO_MODE_UNI)
  1630.         io_mfp_mode = self.mq.get('io-mfp-mode', IO_MODE_UNI)
  1631.         status_code = STATUS_UNKNOWN
  1632.  
  1633.         # Turn off status if local connection and bi-di not avail.
  1634.         #if io_mode  == IO_MODE_UNI and self.back_end != 'net':
  1635.         #    status_type = STATUS_TYPE_NONE
  1636.  
  1637.         agents = []
  1638.  
  1639.         if self.device_state != DEVICE_STATE_NOT_FOUND:
  1640.             if self.tech_type in (TECH_TYPE_MONO_INK, TECH_TYPE_COLOR_INK):
  1641.                 try:
  1642.                     self.getDeviceID()
  1643.                 except Error, e:
  1644.                     log.error("Error getting device ID.")
  1645.                     self.last_event = Event(self.device_uri, '', ERROR_DEVICE_IO_ERROR,
  1646.                         prop.username, 0, '', time.time())
  1647.  
  1648.                     raise Error(ERROR_DEVICE_IO_ERROR)
  1649.  
  1650.             status_desc = self.queryString(self.status_code)
  1651.  
  1652.             self.dq.update({
  1653.                 'serial'           : self.serial,
  1654.                 'cups-printer'     : ','.join(self.cups_printers),
  1655.                 'status-code'      : self.status_code,
  1656.                 'status-desc'      : status_desc,
  1657.                 'deviceid'         : self.raw_deviceID,
  1658.                 'panel'            : 0,
  1659.                 'panel-line1'      : '',
  1660.                 'panel-line2'      : '',
  1661.                 'device-state'     : self.device_state,
  1662.                 'error-state'      : self.error_state,
  1663.                 })
  1664.  
  1665.             status_block = {}
  1666.  
  1667.             if status_type == STATUS_TYPE_NONE:
  1668.                 log.warn("No status available for device.")
  1669.                 status_block = {'status-code' : STATUS_UNKNOWN}
  1670.  
  1671.             elif status_type in (STATUS_TYPE_VSTATUS, STATUS_TYPE_S):
  1672.                 log.debug("Type 1/2 (S: or VSTATUS:) status")
  1673.                 status_block = status.parseStatus(self.deviceID)
  1674.  
  1675.             elif status_type in (STATUS_TYPE_LJ, STATUS_TYPE_PML_AND_PJL):
  1676.                 log.debug("Type 3/9 LaserJet PML(+PJL) status")
  1677.                 status_block = status.StatusType3(self, self.deviceID)
  1678.  
  1679.             elif status_type == STATUS_TYPE_LJ_XML:
  1680.                 log.debug("Type 6: LJ XML")
  1681.                 status_block = status.StatusType6(self)
  1682.  
  1683.             elif status_type == STATUS_TYPE_PJL:
  1684.                 log.debug("Type 8: LJ PJL")
  1685.                 status_block = status.StatusType8(self)
  1686.  
  1687.             else:
  1688.                 log.error("Unimplemented status type: %d" % status_type)
  1689.  
  1690.             if battery_check and \
  1691.                 io_mode != IO_MODE_UNI:
  1692.  
  1693.                 log.debug("Battery check...")
  1694.                 status.BatteryCheck(self, status_block, battery_check)
  1695.  
  1696.             if status_block:
  1697.                 log.debug(status_block)
  1698.                 self.dq.update(status_block)
  1699.                 try:
  1700.                     status_block['agents']
  1701.                 except KeyError:
  1702.                     pass
  1703.                 else:
  1704.                     agents = status_block['agents']
  1705.                     del self.dq['agents']
  1706.  
  1707.  
  1708.             status_code = self.dq.get('status-code', STATUS_UNKNOWN)
  1709.  
  1710. ##            if not quick and \
  1711. ##                self.mq.get('fax-type', FAX_TYPE_NONE) and \
  1712. ##                status_code == STATUS_PRINTER_IDLE and \
  1713. ##                io_mode != IO_MODE_UNI:
  1714. ##
  1715. ##                log.debug("Fax activity check...")
  1716. ##
  1717. ##                tx_active, rx_active = status.getFaxStatus(self)
  1718. ##
  1719. ##                if tx_active:
  1720. ##                    status_code = STATUS_FAX_TX_ACTIVE
  1721. ##                elif rx_active:
  1722. ##                    status_code = STATUS_FAX_RX_ACTIVE
  1723.  
  1724.  
  1725.             self.error_state = STATUS_TO_ERROR_STATE_MAP.get(status_code, ERROR_STATE_CLEAR)
  1726.             self.error_code = status_code
  1727.             self.sendEvent(self.error_code)
  1728.  
  1729.             #print "Error state=", self.error_state, self.device_uri
  1730.  
  1731.             try:
  1732.                 self.dq.update({'status-desc' : self.queryString(status_code),
  1733.                                 'error-state' : self.error_state,
  1734.                                 })
  1735.  
  1736.             except (KeyError, Error):
  1737.                 self.dq.update({'status-desc' : '',
  1738.                                 'error-state' : ERROR_STATE_CLEAR,
  1739.                                 })
  1740.  
  1741.             r_value = 0
  1742.  
  1743.             if not quick and status_type != STATUS_TYPE_NONE:
  1744.                 if self.panel_check:
  1745.                     self.panel_check = bool(self.mq.get('panel-check-type', 0))
  1746.  
  1747.                 if self.panel_check and \
  1748.                     status_type in (STATUS_TYPE_LJ, STATUS_TYPE_S, STATUS_TYPE_VSTATUS) and \
  1749.                     io_mode != IO_MODE_UNI:
  1750.  
  1751.                     log.debug("Panel check...")
  1752.                     try:
  1753.                         self.panel_check, line1, line2 = status.PanelCheck(self)
  1754.                     finally:
  1755.                         self.closePML()
  1756.  
  1757.                     self.dq.update({'panel': int(self.panel_check),
  1758.                                       'panel-line1': line1,
  1759.                                       'panel-line2': line2,})
  1760.  
  1761.  
  1762.                 if dynamic_counters != STATUS_DYNAMIC_COUNTERS_NONE and \
  1763.                     io_mode != IO_MODE_UNI:
  1764.  
  1765.                     r_value, r_value_str, rg, rr = self.getRValues(r_type, status_type, dynamic_counters)
  1766.                 else:
  1767.                     r_value, r_value_str, rg, rr = 0, '000000000', '000', '000000'
  1768.  
  1769.                 self.dq.update({'r'  : r_value,
  1770.                                 'rs' : r_value_str,
  1771.                                 'rg' : rg,
  1772.                                 'rr' : rr,
  1773.                               })
  1774.  
  1775.             if not quick and reread_cups_printers:
  1776.                 self.cups_printers = []
  1777.                 log.debug("Re-reading CUPS printer queue information.")
  1778.                 printers = cups.getPrinters()
  1779.                 for p in printers:
  1780.                     if self.device_uri == p.device_uri:
  1781.                         self.cups_printers.append(p.name)
  1782.                         self.state = p.state # ?
  1783.  
  1784.                         if self.io_state == IO_STATE_NON_HP:
  1785.                             self.model = p.makemodel.split(',')[0]
  1786.  
  1787.                 self.dq.update({'cups-printer' : ','.join(self.cups_printers)})
  1788.  
  1789.                 try:
  1790.                     self.first_cups_printer = self.cups_printers[0]
  1791.                 except IndexError:
  1792.                     self.first_cups_printer = ''
  1793.  
  1794.             if not quick:
  1795.                 # Make sure there is some valid agent data for this r_value
  1796.                 # If not, fall back to r_value == 0
  1797.                 if r_value > 0 and self.mq.get('r%d-agent1-kind' % r_value, 0) == 0:
  1798.                     r_value = 0
  1799.                     self.dq.update({'r'  : r_value,
  1800.                                     'rs' : r_value_str,
  1801.                                     'rg' : rg,
  1802.                                     'rr' : rr,
  1803.                                   })
  1804.  
  1805.                 a, aa = 1, 1
  1806.                 while True:
  1807.                     mq_agent_kind = self.mq.get('r%d-agent%d-kind' % (r_value, a), -1)
  1808.  
  1809.                     if mq_agent_kind == -1:
  1810.                         break
  1811.  
  1812.                     mq_agent_type = self.mq.get('r%d-agent%d-type' % (r_value, a), 0)
  1813.                     mq_agent_sku = self.mq.get('r%d-agent%d-sku' % (r_value, a), '')
  1814.  
  1815.                     found = False
  1816.  
  1817.                     log.debug("Looking for kind=%d, type=%d..." % (mq_agent_kind, mq_agent_type))
  1818.                     for agent in agents:
  1819.                         agent_kind = agent['kind']
  1820.                         agent_type = agent['type']
  1821.  
  1822.                         if agent_kind == mq_agent_kind and \
  1823.                            agent_type == mq_agent_type:
  1824.                            found = True
  1825.                            break
  1826.  
  1827.                     if found:
  1828.                         log.debug("found: r%d-kind%d-type%d" % (r_value, agent_kind, agent_type))
  1829.  
  1830.                         agent_health = agent.get('health', AGENT_HEALTH_OK)
  1831.                         agent_level = agent.get('level', 100)
  1832.                         agent_level_trigger = agent.get('level-trigger',
  1833.                             AGENT_LEVEL_TRIGGER_SUFFICIENT_0)
  1834.  
  1835.                         log.debug("health=%d, level=%d, level_trigger=%d, status_code=%d" %
  1836.                             (agent_health, agent_level, agent_level_trigger, status_code))
  1837.  
  1838.                         query = 'agent_%s_%s' % (AGENT_types.get(agent_type, 'unknown'),
  1839.                                                  AGENT_kinds.get(agent_kind, 'unknown'))
  1840.  
  1841.                         agent_desc = self.queryString(query)
  1842.                         query = 'agent_health_ok'
  1843.  
  1844.                         # If printer is not in an error state, and
  1845.                         # if agent health is OK, check for low supplies. If low, use
  1846.                         # the agent level trigger description for the agent description.
  1847.                         # Otherwise, report the agent health.
  1848.                         if (status_code == STATUS_PRINTER_IDLE or status_code == STATUS_PRINTER_OUT_OF_INK) and \
  1849.                             (agent_health == AGENT_HEALTH_OK or
  1850.                              (agent_health == AGENT_HEALTH_FAIR_MODERATE and agent_kind == AGENT_KIND_HEAD)) and \
  1851.                             agent_level_trigger >= AGENT_LEVEL_TRIGGER_MAY_BE_LOW:
  1852.  
  1853.                             query = 'agent_level_%s' % AGENT_levels.get(agent_level_trigger, 'unknown')
  1854.  
  1855.                             if tech_type in (TECH_TYPE_MONO_INK, TECH_TYPE_COLOR_INK):
  1856.                                 code = agent_type + STATUS_PRINTER_LOW_INK_BASE
  1857.                             else:
  1858.                                 code = agent_type + STATUS_PRINTER_LOW_TONER_BASE
  1859.  
  1860.                             self.dq['status-code'] = code
  1861.                             self.dq['status-desc'] = self.queryString(code)
  1862.  
  1863.                             self.dq['error-state'] = STATUS_TO_ERROR_STATE_MAP.get(code, ERROR_STATE_LOW_SUPPLIES)
  1864.                             self.error_code = code
  1865.                             self.sendEvent(self.error_code)
  1866.  
  1867.                             if agent_level_trigger in \
  1868.                                 (AGENT_LEVEL_TRIGGER_PROBABLY_OUT, AGENT_LEVEL_TRIGGER_ALMOST_DEFINITELY_OUT):
  1869.  
  1870.                                 query = 'agent_level_out'
  1871.                             else:
  1872.                                 query = 'agent_level_low'
  1873.  
  1874.                             agent_health_desc = self.queryString(query)
  1875.  
  1876.                             self.dq.update(
  1877.                             {
  1878.                                 'agent%d-kind' % aa :          agent_kind,
  1879.                                 'agent%d-type' % aa :          agent_type,
  1880.                                 'agent%d-known' % aa :         agent.get('known', False),
  1881.                                 'agent%d-sku' % aa :           mq_agent_sku,
  1882.                                 'agent%d-level' % aa :         agent_level,
  1883.                                 'agent%d-level-trigger' % aa : agent_level_trigger,
  1884.                                 'agent%d-ack' % aa :           agent.get('ack', False),
  1885.                                 'agent%d-hp-ink' % aa :        agent.get('hp-ink', False),
  1886.                                 'agent%d-health' % aa :        agent_health,
  1887.                                 'agent%d-dvc' % aa :           agent.get('dvc', 0),
  1888.                                 'agent%d-virgin' % aa :        agent.get('virgin', False),
  1889.                                 'agent%d-desc' % aa :          agent_desc,
  1890.                                 'agent%d-id' % aa :            agent.get('id', 0),
  1891.                                 'agent%d-health-desc' % aa :   agent_health_desc,
  1892.                             })
  1893.  
  1894.                         else:
  1895.                             query = 'agent_health_%s' % AGENT_healths.get(agent_health, AGENT_HEALTH_OK)
  1896.                             agent_health_desc = self.queryString(query)
  1897.  
  1898.                             self.dq.update(
  1899.                             {
  1900.                                 'agent%d-kind' % aa :          agent_kind,
  1901.                                 'agent%d-type' % aa :          agent_type,
  1902.                                 'agent%d-known' % aa :         False,
  1903.                                 'agent%d-sku' % aa :           mq_agent_sku,
  1904.                                 'agent%d-level' % aa :         agent_level,
  1905.                                 'agent%d-level-trigger' % aa : agent_level_trigger,
  1906.                                 'agent%d-ack' % aa :           False,
  1907.                                 'agent%d-hp-ink' % aa :        False,
  1908.                                 'agent%d-health' % aa :        agent_health,
  1909.                                 'agent%d-dvc' % aa :           0,
  1910.                                 'agent%d-virgin' % aa :        False,
  1911.                                 'agent%d-desc' % aa :          agent_desc,
  1912.                                 'agent%d-id' % aa :            0,
  1913.                                 'agent%d-health-desc' % aa :   agent_health_desc,
  1914.                             })
  1915.  
  1916.                         aa += 1
  1917.  
  1918.                     else:
  1919.                         log.debug("Not found: %d" % a)
  1920.  
  1921.                     a += 1
  1922.  
  1923.         else: # Create agent keys for not-found devices
  1924.  
  1925.             r_value = 0
  1926.             if r_type > 0 and self.r_values is not None:
  1927.                 r_value = self.r_values[0]
  1928.  
  1929.             # Make sure there is some valid agent data for this r_value
  1930.             # If not, fall back to r_value == 0
  1931.             if r_value > 0 and self.mq.get('r%d-agent1-kind', 0) == 0:
  1932.                 r_value = 0
  1933.  
  1934.             a = 1
  1935.             while True:
  1936.                 mq_agent_kind = self.mq.get('r%d-agent%d-kind' % (r_value, a), 0)
  1937.  
  1938.                 if mq_agent_kind == 0:
  1939.                     break
  1940.  
  1941.                 mq_agent_type = self.mq.get('r%d-agent%d-type' % (r_value, a), 0)
  1942.                 mq_agent_sku = self.mq.get('r%d-agent%d-sku' % (r_value, a), '')
  1943.                 query = 'agent_%s_%s' % (AGENT_types.get(mq_agent_type, 'unknown'),
  1944.                                          AGENT_kinds.get(mq_agent_kind, 'unknown'))
  1945.  
  1946.                 agent_desc = self.queryString(query)
  1947.  
  1948.                 self.dq.update(
  1949.                 {
  1950.                     'agent%d-kind' % a :          mq_agent_kind,
  1951.                     'agent%d-type' % a :          mq_agent_type,
  1952.                     'agent%d-known' % a :         False,
  1953.                     'agent%d-sku' % a :           mq_agent_sku,
  1954.                     'agent%d-level' % a :         0,
  1955.                     'agent%d-level-trigger' % a : AGENT_LEVEL_TRIGGER_ALMOST_DEFINITELY_OUT,
  1956.                     'agent%d-ack' % a :           False,
  1957.                     'agent%d-hp-ink' % a :        False,
  1958.                     'agent%d-health' % a :        AGENT_HEALTH_MISINSTALLED,
  1959.                     'agent%d-dvc' % a :           0,
  1960.                     'agent%d-virgin' % a :        False,
  1961.                     'agent%d-health-desc' % a :   self.queryString('agent_health_unknown'),
  1962.                     'agent%d-desc' % a :          agent_desc,
  1963.                     'agent%d-id' % a :            0,
  1964.                 })
  1965.  
  1966.                 a += 1
  1967.  
  1968.         for d in self.dq:
  1969.             self.__dict__[d.replace('-','_')] = self.dq[d]
  1970.  
  1971.         self.last_event = Event(self.device_uri, '', status_code, prop.username, 0, '', time.time())
  1972.         log.debug(self.dq)
  1973.  
  1974.  
  1975.     def isBusyOrInErrorState(self):
  1976.         try:
  1977.             self.queryDevice(quick=True)
  1978.         except Error:
  1979.             return True
  1980.         return self.error_state in (ERROR_STATE_ERROR, ERROR_STATE_BUSY)
  1981.  
  1982.  
  1983.     def isIdleAndNoError(self):
  1984.         try:
  1985.             self.queryDevice(quick=True)
  1986.         except Error:
  1987.             return False
  1988.         return self.error_state not in (ERROR_STATE_ERROR, ERROR_STATE_BUSY)
  1989.  
  1990.  
  1991.     def getPML(self, oid, desired_int_size=pml.INT_SIZE_INT): # oid => ( 'dotted oid value', pml type )
  1992.         channel_id = self.openPML()
  1993.  
  1994.         result_code, data, typ, pml_result_code = \
  1995.             hpmudext.get_pml(self.device_id, channel_id, pml.PMLToSNMP(oid[0]), oid[1])
  1996.  
  1997.         if pml_result_code > pml.ERROR_MAX_OK:
  1998.             log.debug("PML/SNMP GET %s failed (result code = 0x%x)" % (oid[0], pml_result_code))
  1999.             return pml_result_code, None
  2000.  
  2001.         converted_data = pml.ConvertFromPMLDataFormat(data, oid[1], desired_int_size)
  2002.  
  2003.         if log.is_debug():
  2004.             if oid[1] in (pml.TYPE_STRING, pml.TYPE_BINARY):
  2005.  
  2006.                 log.debug("PML/SNMP GET %s (result code = 0x%x) returned:" %
  2007.                     (oid[0], pml_result_code))
  2008.                 log.log_data(data)
  2009.             else:
  2010.                 log.debug("PML/SNMP GET %s (result code = 0x%x) returned: %s" %
  2011.                     (oid[0], pml_result_code, repr(converted_data)))
  2012.  
  2013.         return pml_result_code, converted_data
  2014.  
  2015.  
  2016.     def setPML(self, oid, value): # oid => ( 'dotted oid value', pml type )
  2017.         channel_id = self.openPML()
  2018.  
  2019.         value = pml.ConvertToPMLDataFormat(value, oid[1])
  2020.  
  2021.         result_code, pml_result_code = \
  2022.             hpmudext.set_pml(self.device_id, channel_id, pml.PMLToSNMP(oid[0]), oid[1], value)
  2023.  
  2024.         if log.is_debug():
  2025.             if oid[1] in (pml.TYPE_STRING, pml.TYPE_BINARY):
  2026.  
  2027.                 log.debug("PML/SNMP SET %s (result code = 0x%x) to:" %
  2028.                     (oid[0], pml_result_code))
  2029.                 log.log_data(value)
  2030.             else:
  2031.                 log.debug("PML/SNMP SET %s (result code = 0x%x) to: %s" %
  2032.                     (oid[0], pml_result_code, repr(value)))
  2033.  
  2034.         return pml_result_code
  2035.  
  2036.  
  2037.     def getDynamicCounter(self, counter, convert_to_int=True):
  2038.         dynamic_counters = self.mq.get('status-dynamic-counters', STATUS_DYNAMIC_COUNTERS_NONE)
  2039.         log.debug("Dynamic counters: %d" % dynamic_counters)
  2040.         if dynamic_counters != STATUS_DYNAMIC_COUNTERS_NONE:
  2041.  
  2042.             if dynamic_counters == STATUS_DYNAMIC_COUNTERS_LIDIL_0_5_4:
  2043.                 self.printData(ldl.buildResetPacket(), direct=True)
  2044.                 self.printData(ldl.buildDynamicCountersPacket(counter), direct=True)
  2045.             else:
  2046.                 self.printData(pcl.buildDynamicCounter(counter), direct=True)
  2047.  
  2048.             value, tries, times_seen, sleepy_time, max_tries = 0, 0, 0, 0.1, 5
  2049.             time.sleep(0.1)
  2050.  
  2051.             while True:
  2052.  
  2053.                 if self.callback:
  2054.                     self.callback()
  2055.  
  2056.                 sleepy_time += 0.1
  2057.                 tries += 1
  2058.  
  2059.                 time.sleep(sleepy_time)
  2060.  
  2061.                 self.getDeviceID()
  2062.  
  2063.                 if 'CTR' in self.deviceID and \
  2064.                     pat_dynamic_ctr.search(self.raw_deviceID) is not None:
  2065.                     dev_counter, value = parseDynamicCounter(self.deviceID['CTR'], convert_to_int)
  2066.  
  2067.                     if counter == dev_counter:
  2068.                         self.printData(pcl.buildDynamicCounter(0), direct=True)
  2069.                         # protect the value as a string during msg handling
  2070.                         if not convert_to_int:
  2071.                             value = '#' + value
  2072.                         return value
  2073.  
  2074.                 if tries > max_tries:
  2075.                     if dynamic_counters == STATUS_DYNAMIC_COUNTERS_LIDIL_0_5_4:
  2076.                         self.printData(ldl.buildResetPacket())
  2077.                         self.printData(ldl.buildDynamicCountersPacket(counter), direct=True)
  2078.                     else:
  2079.                         self.printData(pcl.buildDynamicCounter(0), direct=True)
  2080.  
  2081.                     return None
  2082.  
  2083.                 if dynamic_counters == STATUS_DYNAMIC_COUNTERS_LIDIL_0_5_4:
  2084.                     self.printData(ldl.buildResetPacket())
  2085.                     self.printData(ldl.buildDynamicCountersPacket(counter), direct=True)
  2086.                 else:
  2087.                     self.printData(pcl.buildDynamicCounter(counter), direct=True)
  2088.  
  2089.         else:
  2090.             raise Error(ERROR_DEVICE_DOES_NOT_SUPPORT_OPERATION)
  2091.  
  2092.  
  2093.     def readPrint(self, bytes_to_read, stream=None, timeout=prop.read_timeout, allow_short_read=False):
  2094.         return self.__readChannel(self.openPrint, bytes_to_read, stream, timeout, allow_short_read)
  2095.  
  2096.     def readPCard(self, bytes_to_read, stream=None, timeout=prop.read_timeout, allow_short_read=False):
  2097.         return self.__readChannel(self.openPCard, bytes_to_read, stream, timeout, allow_short_read)
  2098.  
  2099.     def readFax(self, bytes_to_read, stream=None, timeout=prop.read_timeout, allow_short_read=False):
  2100.         return self.__readChannel(self.openFax, bytes_to_read, stream, timeout, allow_short_read)
  2101.  
  2102.     def readCfgUpload(self, bytes_to_read, stream=None, timeout=prop.read_timeout, allow_short_read=False):
  2103.         return self.__readChannel(self.openCfgUpload, bytes_to_read, stream, timeout, allow_short_read)
  2104.  
  2105.     def readEWS(self, bytes_to_read, stream=None, timeout=prop.read_timeout, allow_short_read=True):
  2106.         return self.__readChannel(self.openEWS, bytes_to_read, stream, timeout, allow_short_read)
  2107.  
  2108.     def readSoapFax(self, bytes_to_read, stream=None, timeout=prop.read_timeout, allow_short_read=True):
  2109.         return self.__readChannel(self.openSoapFax, bytes_to_read, stream, timeout, allow_short_read)
  2110.  
  2111.     def __readChannel(self, opener, bytes_to_read, stream=None,
  2112.                       timeout=prop.read_timeout, allow_short_read=False):
  2113. #       print "__readChannel()"
  2114. #       raise Error(ERROR_DEVICE_IO_ERROR)
  2115. #       return 0
  2116.  
  2117.         channel_id = opener()
  2118.  
  2119.         log.debug("Reading channel %d..." % channel_id)
  2120.  
  2121.         num_bytes = 0
  2122.  
  2123.         if stream is None:
  2124.             buffer = ''
  2125.  
  2126.         while True:
  2127.             result_code, data = \
  2128.                 hpmudext.read_channel(self.device_id, channel_id, bytes_to_read, timeout)
  2129.  
  2130.             l = len(data)
  2131.  
  2132.             if result_code == hpmudext.HPMUD_R_IO_TIMEOUT:
  2133.                 log.debug("I/O timeout")
  2134.                 break
  2135.  
  2136.             if result_code != hpmudext.HPMUD_R_OK:
  2137.                 log.error("Channel read error")
  2138.                 raise Error(ERROR_DEVICE_IO_ERROR)
  2139.  
  2140.             if not l:
  2141.                 log.debug("End of data")
  2142.                 break
  2143.  
  2144.             if stream is None:
  2145.                 buffer = ''.join([buffer, data])
  2146.             else:
  2147.                 stream.write(data)
  2148.  
  2149.             num_bytes += l
  2150.  
  2151.             if self.callback is not None:
  2152.                 self.callback()
  2153.  
  2154.             if num_bytes == bytes_to_read:
  2155.                 log.debug("Full read complete.")
  2156.                 break
  2157.  
  2158.             if allow_short_read and num_bytes < bytes_to_read:
  2159.                 log.debug("Allowed short read of %d of %d bytes complete." % (num_bytes, bytes_to_read))
  2160.                 break
  2161.  
  2162.         if stream is None:
  2163.             log.debug("Returned %d total bytes in buffer." % num_bytes)
  2164.             return buffer
  2165.         else:
  2166.             log.debug("Saved %d total bytes to stream." % num_bytes)
  2167.             return num_bytes
  2168.  
  2169.  
  2170.     def writePrint(self, data):
  2171.         return self.__writeChannel(self.openPrint, data)
  2172.  
  2173.     def writePCard(self, data):
  2174.         return self.__writeChannel(self.openPCard, data)
  2175.  
  2176.     def writeFax(self, data):
  2177.         return self.__writeChannel(self.openFax, data)
  2178.  
  2179.     def writeEWS(self, data):
  2180.         return self.__writeChannel(self.openEWS, data)
  2181.  
  2182.     def writeCfgDownload(self, data):
  2183.         return self.__writeChannel(self.openCfgDownload, data)
  2184.  
  2185.     def writeSoapFax(self, data):
  2186.         return self.__writeChannel(self.openSoapFax, data)
  2187.  
  2188.  
  2189.     def __writeChannel(self, opener, data):
  2190. #       print "__writeChannel()"
  2191. #       raise Error(ERROR_DEVICE_IO_ERROR)
  2192. #       return 0
  2193.  
  2194.         channel_id = opener()
  2195.  
  2196.         buffer, bytes_out, total_bytes_to_write = data, 0, len(data)
  2197.         log.debug("Writing %d bytes to channel %d..." % (total_bytes_to_write,channel_id))
  2198.  
  2199.         while len(buffer) > 0:
  2200.             result_code, bytes_written = \
  2201.                 hpmudext.write_channel(self.device_id, channel_id,
  2202.                     buffer[:prop.max_message_len])
  2203.  
  2204.             if result_code != hpmudext.HPMUD_R_OK:
  2205.                 log.error("Channel write error")
  2206.                 raise Error(ERROR_DEVICE_IO_ERROR)
  2207.  
  2208.             buffer = buffer[prop.max_message_len:]
  2209.             bytes_out += bytes_written
  2210.  
  2211.             if self.callback is not None:
  2212.                 self.callback()
  2213.  
  2214.         if total_bytes_to_write != bytes_out:
  2215.             raise Error(ERROR_DEVICE_IO_ERROR)
  2216.  
  2217.         return bytes_out
  2218.  
  2219.  
  2220.     def writeEmbeddedPML(self, oid, value, style=1, direct=True):
  2221.         if style == 1:
  2222.             func = pcl.buildEmbeddedPML2
  2223.         else:
  2224.             func = pcl.buildEmbeddedPML
  2225.  
  2226.         data = func(pcl.buildPCLCmd('&', 'b', 'W',
  2227.                      pml.buildEmbeddedPMLSetPacket(oid[0],
  2228.                                                     value,
  2229.                                                     oid[1])))
  2230.  
  2231.         log.log_data(data)
  2232.  
  2233.         self.printData(data, direct=direct, raw=True)
  2234.  
  2235.  
  2236.     def printGzipFile(self, file_name, printer_name=None, direct=False, raw=True, remove=False):
  2237.         return self.printFile(file_name, printer_name, direct, raw, remove)
  2238.  
  2239.     def printParsedGzipPostscript(self, print_file, printer_name=None):
  2240.         # always: direct=False, raw=False, remove=True
  2241.         try:
  2242.             os.stat(print_file)
  2243.         except OSError:
  2244.             log.error("File not found: %s" % print_file)
  2245.             return
  2246.  
  2247.         temp_file_fd, temp_file_name = utils.make_temp_file()
  2248.         f = gzip.open(print_file, 'r')
  2249.  
  2250.         x = f.readline()
  2251.         while not x.startswith('%PY_BEGIN'):
  2252.             os.write(temp_file_fd, x)
  2253.             x = f.readline()
  2254.  
  2255.         sub_lines = []
  2256.         x = f.readline()
  2257.         while not x.startswith('%PY_END'):
  2258.             sub_lines.append(x)
  2259.             x = f.readline()
  2260.  
  2261.         SUBS = {'VERSION' : prop.version,
  2262.                  'MODEL'   : self.model_ui,
  2263.                  'URI'     : self.device_uri,
  2264.                  'BUS'     : self.bus,
  2265.                  'SERIAL'  : self.serial,
  2266.                  'IP'      : self.host,
  2267.                  'PORT'    : self.port,
  2268.                  'DEVNODE' : self.dev_file,
  2269.                  }
  2270.  
  2271.         if self.bus == 'net':
  2272.             SUBS['DEVNODE'] = 'n/a'
  2273.         else:
  2274.             SUBS['IP'] = 'n/a'
  2275.             SUBS['PORT'] = 'n/a'
  2276.  
  2277.         for s in sub_lines:
  2278.             os.write(temp_file_fd, s % SUBS)
  2279.  
  2280.         os.write(temp_file_fd, f.read())
  2281.         f.close()
  2282.         os.close(temp_file_fd)
  2283.  
  2284.         self.printFile(temp_file_name, printer_name, direct=False, raw=False, remove=True)
  2285.  
  2286.     def printFile(self, file_name, printer_name=None, direct=False, raw=True, remove=False):
  2287.         is_gzip = os.path.splitext(file_name)[-1].lower() == '.gz'
  2288.  
  2289.         if printer_name is None:
  2290.             try:
  2291.                 printer_name = self.cups_printers[0]
  2292.             except IndexError:
  2293.                 raise Error(ERROR_NO_CUPS_QUEUE_FOUND_FOR_DEVICE)
  2294.  
  2295.         log.debug("Printing file '%s' to queue '%s' (gzip=%s, direct=%s, raw=%s, remove=%s)" %
  2296.                    (file_name, printer_name, is_gzip, direct, raw, remove))
  2297.  
  2298.         if direct: # implies raw==True
  2299.             if is_gzip:
  2300.                 self.writePrint(gzip.open(file_name, 'r').read())
  2301.             else:
  2302.                 self.writePrint(file(file_name, 'r').read())
  2303.  
  2304.         else:
  2305.             if not utils.which('lpr'):
  2306.                 lp_opt = ''
  2307.  
  2308.                 if raw:
  2309.                     lp_opt = '-oraw'
  2310.  
  2311.                 if is_gzip:
  2312.                     c = 'gunzip -c %s | lp -c -d%s %s' % (file_name, printer_name, lp_opt)
  2313.                 else:
  2314.                     c = 'lp -c -d%s %s %s' % (printer_name, lp_opt, file_name)
  2315.  
  2316.                 log.debug(c)
  2317.                 exit_code = os.system(c)
  2318.  
  2319.                 if exit_code != 0:
  2320.                     log.error("Print command failed with exit code %d!" % exit_code)
  2321.  
  2322.                 if remove:
  2323.                     os.remove(file_name)
  2324.  
  2325.             else:
  2326.                 raw_str, rem_str = '', ''
  2327.                 if raw: raw_str = '-o raw'
  2328.                 if remove: rem_str = '-r'
  2329.  
  2330.                 if is_gzip:
  2331.                     c = 'gunzip -c %s | lpr %s %s -P%s' % (file_name, raw_str, rem_str, printer_name)
  2332.                 else:
  2333.                     c = 'lpr -P%s %s %s %s' % (printer_name, raw_str, rem_str, file_name)
  2334.  
  2335.                 log.debug(c)
  2336.                 exit_code = os.system(c)
  2337.  
  2338.                 if exit_code != 0:
  2339.                     log.error("Print command failed with exit code %d!" % exit_code)
  2340.  
  2341.  
  2342.     def printTestPage(self, printer_name=None):
  2343.         return self.printParsedGzipPostscript(os.path.join( prop.home_dir, 'data',
  2344.                                               'ps', 'testpage.ps.gz' ), printer_name)
  2345.  
  2346.  
  2347.     def printData(self, data, printer_name=None, direct=True, raw=True):
  2348.         #log.log_data(data)
  2349.         #log.debug("printData(direct=%s, raw=%s)" % (direct, raw))
  2350.         if direct:
  2351.             self.writePrint(data)
  2352.         else:
  2353.             temp_file_fd, temp_file_name = utils.make_temp_file()
  2354.             os.write(temp_file_fd, data)
  2355.             os.close(temp_file_fd)
  2356.  
  2357.             self.printFile(temp_file_name, printer_name, False, raw, remove=True)
  2358.  
  2359.  
  2360.     def cancelJob(self, jobid):
  2361.         cups.cancelJob(jobid)
  2362.         self.error_code = STATUS_PRINTER_CANCELING
  2363.         self.sendEvent(self.error_code)
  2364.  
  2365.  
  2366.     def queryHistory(self):
  2367.         result = []
  2368.  
  2369.         if self.dbus_avail:
  2370.             try:
  2371.                 device_uri, history = self.service.GetHistory(self.device_uri)
  2372.             except dbus.exceptions.DBusException, e:
  2373.                 log.error("dbus call to GetHistory() failed.")
  2374.                 return []
  2375.  
  2376.             history.reverse()
  2377.  
  2378.             for h in history:
  2379.                 result.append(Event(*tuple(h)))
  2380.  
  2381.             try:
  2382.                 self.error_code = result[0].event_code
  2383.             except IndexError:
  2384.                 self.error_code = STATUS_UNKNOWN
  2385.  
  2386.             self.error_state = STATUS_TO_ERROR_STATE_MAP.get(self.error_code, ERROR_STATE_CLEAR)
  2387.  
  2388.         else:
  2389.             self.error_code = STATUS_UNKNOWN
  2390.             self.error_state = ERROR_STATE_CLEAR
  2391.  
  2392.         self.hist = result
  2393.         return result
  2394.  
  2395.  
  2396.  
  2397.     def getEWSUrl(self, url, stream):
  2398.         try:
  2399.             if self.is_local:
  2400.                 url2 = "%s&loc=%s" % (self.device_uri.replace('hpfax:', 'hp:'), url)
  2401.                 data = self
  2402.             else:
  2403.                 url2 = "http://%s%s" % (self.host, url)
  2404.                 data = None
  2405.  
  2406.             log.debug("Opening: %s" % url2)
  2407.             opener = LocalOpener({})
  2408.             try:
  2409.                 f = opener.open(url2, data)
  2410.             except Error:
  2411.                 log.error("Status read failed: %s" % url2)
  2412.                 stream.seek(0)
  2413.                 stream.truncate()
  2414.             else:
  2415.                 try:
  2416.                     stream.write(f.read())
  2417.                 finally:
  2418.                     f.close()
  2419.  
  2420.         finally:
  2421.             self.closeEWS()
  2422.  
  2423.  
  2424.     def downloadFirmware(self, usb_bus_id=None, usb_device_id=None): # Note: IDs not currently used
  2425.         ok = False
  2426.         filename = os.path.join(prop.data_dir, "firmware", self.model.lower() + '.fw.gz')
  2427.         log.debug(filename)
  2428.  
  2429.         if os.path.exists(filename):
  2430.             log.debug("Downloading firmware file '%s'..." % filename)
  2431.  
  2432.             # Write to port directly (no MUD) so that HAL can enumerate the printer
  2433.             if 0: # this currently doesn't work because usblp is loaded...
  2434.             #if usb_bus_id is not None and usb_device_id is not None:
  2435.                 try:
  2436.                     p = "/dev/bus/usb/%s/%s" % (usb_bus_id, usb_device_id)
  2437.                     log.debug("Writing to %s..." % p)
  2438.                     f = os.open(p, os.O_RDWR)
  2439.                     x = gzip.open(filename).read()
  2440.                     os.write(f, x)
  2441.                     os.close(f)
  2442.                     ok = True
  2443.                     log.debug("OK")
  2444.                 except (OSError, IOError), e:
  2445.                     log.error("An error occured: %s" % e)
  2446.             else:
  2447.                 try:
  2448.                     self.openPrint()
  2449.                     bytes_written = self.writePrint(gzip.open(filename).read())
  2450.                     log.debug("%s bytes downloaded." % utils.commafy(bytes_written))
  2451.                     self.closePrint()
  2452.                     ok = True
  2453.                     log.debug("OK")
  2454.                 except Error, e:
  2455.                     log.error("An error occured: %s" % e.msg)
  2456.         else:
  2457.             log.error("Firmware file '%s' not found." % filename)
  2458.  
  2459.         return ok
  2460.  
  2461.  
  2462. # ********************************** Support classes/functions
  2463.  
  2464.  
  2465. class xStringIO(StringIO.StringIO):
  2466.     def makefile(self, x, y):
  2467.         return self
  2468.  
  2469. # URLs: hp:/usb/HP_LaserJet_3050?serial=00XXXXXXXXXX&loc=/hp/device/info_device_status.xml
  2470. class LocalOpener(urllib.URLopener):
  2471.     def open_hp(self, url, dev):
  2472.         log.debug("open_hp(%s)" % url)
  2473.  
  2474.         match_obj = http_pat_url.search(url)
  2475.         bus = match_obj.group(1) or ''
  2476.         model = match_obj.group(2) or ''
  2477.         serial = match_obj.group(3) or ''
  2478.         device = match_obj.group(4) or ''
  2479.         loc = match_obj.group(5) or ''
  2480.  
  2481.         dev.openEWS()
  2482.         dev.writeEWS("""GET %s HTTP/1.0\nContent-Length:0\nHost:localhost\nUser-Agent:hplip\n\n""" % loc)
  2483.  
  2484.         reply = xStringIO()
  2485.  
  2486.         while dev.readEWS(8192, reply, timeout=1):
  2487.             pass
  2488.  
  2489.         reply.seek(0)
  2490.         log.log_data(reply.getvalue())
  2491.  
  2492.         response = httplib.HTTPResponse(reply)
  2493.         response.begin()
  2494.  
  2495.         if response.status != httplib.OK:
  2496.             raise Error(ERROR_DEVICE_STATUS_NOT_AVAILABLE)
  2497.         else:
  2498.             return response.fp
  2499.  
  2500.  
  2501.